6d8899a078
- 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)
96 lines
3.3 KiB
Go
96 lines
3.3 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
}
|