feat(app): add WGRplane web UI and backend features
- Add Vue 3 frontend with glassmorphism design (Tailwind CSS) - Add Go backend handlers: auth, webhooks, stats, scheduler, validation - Add i18n support (EN, ID, ZH) - Add Swagger docs and API handlers - Add nftables integration and plugins support - Remove deprecated go.mod (migrated to wgrplane)
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
// initScheduler creates and starts the background cron jobs responsible for
|
||||
// peer lifecycle automation: expiry deletion, data-limit restriction, and monthly resets.
|
||||
func initScheduler() *cron.Cron {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
|
||||
// 2:00 AM daily - Delete expired peers
|
||||
if _, err := c.AddFunc("0 0 2 * * *", deleteExpiredPeers); err != nil {
|
||||
log.Printf("scheduler: failed to schedule deleteExpiredPeers: %v", err)
|
||||
}
|
||||
|
||||
// 3:00 AM daily - Disable peers that exceeded data limit
|
||||
if _, err := c.AddFunc("0 0 3 * * *", restrictOverLimitPeers); err != nil {
|
||||
log.Printf("scheduler: failed to schedule restrictOverLimitPeers: %v", err)
|
||||
}
|
||||
|
||||
// 1st day of every month at 00:00 - Reset data usage counters
|
||||
if _, err := c.AddFunc("0 0 0 1 * *", resetMonthlyUsage); err != nil {
|
||||
log.Printf("scheduler: failed to schedule resetMonthlyUsage: %v", err)
|
||||
}
|
||||
|
||||
c.Start()
|
||||
log.Println("scheduler: started background jobs (expiry, data-limit, monthly reset)")
|
||||
return c
|
||||
}
|
||||
|
||||
// deleteExpiredPeers removes peers whose ExpiresAt is non-zero and in the past.
|
||||
func deleteExpiredPeers() {
|
||||
now := time.Now()
|
||||
var peers []Peer
|
||||
if err := db.Where("expires_at != 0 AND expires_at <= ?", now).Find(&peers).Error; err != nil {
|
||||
log.Printf("scheduler: error querying expired peers: %v", err)
|
||||
return
|
||||
}
|
||||
if len(peers) == 0 {
|
||||
log.Println("scheduler: no expired peers to delete")
|
||||
return
|
||||
}
|
||||
for _, p := range peers {
|
||||
if err := db.Delete(&p).Error; err != nil {
|
||||
log.Printf("scheduler: failed to delete peer %d: %v", p.ID, err)
|
||||
} else {
|
||||
log.Printf("scheduler: deleted expired peer %d", p.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restrictOverLimitPeers disables peers that have exceeded their data limit.
|
||||
func restrictOverLimitPeers() {
|
||||
var peers []Peer
|
||||
if err := db.Find(&peers).Error; err != nil {
|
||||
log.Printf("scheduler: error loading peers for restriction: %v", err)
|
||||
return
|
||||
}
|
||||
for _, p := range peers {
|
||||
if p.Enabled && p.DataLimitGB > 0 {
|
||||
limitBytes := p.DataLimitGB * 1_000_000_000
|
||||
if p.CurrentDataUsageBytes >= limitBytes {
|
||||
p.Enabled = false
|
||||
if err := db.Save(&p).Error; err != nil {
|
||||
log.Printf("scheduler: failed to disable peer %d: %v", p.ID, err)
|
||||
} else {
|
||||
log.Printf("scheduler: disabled peer %d due to data limit (%d/%d bytes)", p.ID, p.CurrentDataUsageBytes, limitBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resetMonthlyUsage resets all peers' CurrentDataUsageBytes to zero at the start of each month.
|
||||
func resetMonthlyUsage() {
|
||||
var peers []Peer
|
||||
if err := db.Find(&peers).Error; err != nil {
|
||||
log.Printf("scheduler: error loading peers for monthly reset: %v", err)
|
||||
return
|
||||
}
|
||||
for _, p := range peers {
|
||||
if p.CurrentDataUsageBytes != 0 {
|
||||
p.CurrentDataUsageBytes = 0
|
||||
if err := db.Save(&p).Error; err != nil {
|
||||
log.Printf("scheduler: failed to reset usage for peer %d: %v", p.ID, err)
|
||||
} else {
|
||||
log.Printf("scheduler: reset monthly usage for peer %d", p.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user