mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-12 21:20:07 +00:00
124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
package job
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"x-ui/database/model"
|
|
"x-ui/logger"
|
|
"x-ui/web/service"
|
|
)
|
|
|
|
const (
|
|
resetTypeNever = "never"
|
|
resetTypeDaily = "daily"
|
|
resetTypeWeekly = "weekly"
|
|
resetTypeMonthly = "monthly"
|
|
)
|
|
|
|
var validResetTypes = map[string]bool{
|
|
resetTypeNever: true,
|
|
resetTypeDaily: true,
|
|
resetTypeWeekly: true,
|
|
resetTypeMonthly: true,
|
|
}
|
|
|
|
type PeriodicTrafficResetJob struct {
|
|
inboundService service.InboundService
|
|
lastResetTimes map[string]time.Time
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
func NewPeriodicTrafficResetJob() *PeriodicTrafficResetJob {
|
|
return &PeriodicTrafficResetJob{
|
|
lastResetTimes: make(map[string]time.Time),
|
|
mu: sync.RWMutex{},
|
|
}
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) Run() {
|
|
inbounds, err := j.inboundService.GetAllInbounds()
|
|
if err != nil {
|
|
logger.Warning("Failed to get inbounds for traffic reset:", err)
|
|
return
|
|
}
|
|
|
|
resetCount := 0
|
|
now := time.Now()
|
|
|
|
for _, inbound := range inbounds {
|
|
if !j.shouldResetTraffic(inbound, now) {
|
|
continue
|
|
}
|
|
|
|
if err := j.inboundService.ResetAllClientTraffics(inbound.Id); err != nil {
|
|
logger.Warning("Failed to reset traffic for inbound", inbound.Id, ":", err)
|
|
continue
|
|
}
|
|
|
|
j.updateLastResetTime(inbound, now)
|
|
resetCount++
|
|
logger.Infof("Reset traffic for inbound %d (%s)", inbound.Id, inbound.Remark)
|
|
}
|
|
|
|
if resetCount > 0 {
|
|
logger.Infof("Periodic traffic reset completed: %d inbounds reset", resetCount)
|
|
}
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) shouldResetTraffic(inbound *model.Inbound, now time.Time) bool {
|
|
if !validResetTypes[inbound.PeriodicTrafficReset] || inbound.PeriodicTrafficReset == resetTypeNever {
|
|
return false
|
|
}
|
|
|
|
resetKey := j.getResetKey(inbound)
|
|
lastReset := j.getLastResetTime(resetKey)
|
|
|
|
switch inbound.PeriodicTrafficReset {
|
|
case resetTypeDaily:
|
|
return j.shouldResetDaily(now, lastReset)
|
|
case resetTypeWeekly:
|
|
return j.shouldResetWeekly(now, lastReset)
|
|
case resetTypeMonthly:
|
|
return j.shouldResetMonthly(now, lastReset)
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) shouldResetDaily(now, lastReset time.Time) bool {
|
|
if lastReset.IsZero() {
|
|
return now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
return now.Sub(lastReset) >= 24*time.Hour && now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) shouldResetWeekly(now, lastReset time.Time) bool {
|
|
if lastReset.IsZero() {
|
|
return now.Weekday() == time.Sunday && now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
return now.Sub(lastReset) >= 7*24*time.Hour && now.Weekday() == time.Sunday && now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) shouldResetMonthly(now, lastReset time.Time) bool {
|
|
if lastReset.IsZero() {
|
|
return now.Day() == 1 && now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
return now.Sub(lastReset) >= 28*24*time.Hour && now.Day() == 1 && now.Hour() == 0 && now.Minute() < 10
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) getResetKey(inbound *model.Inbound) string {
|
|
return inbound.PeriodicTrafficReset + "_" + inbound.Tag
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) getLastResetTime(key string) time.Time {
|
|
j.mu.RLock()
|
|
defer j.mu.RUnlock()
|
|
return j.lastResetTimes[key]
|
|
}
|
|
|
|
func (j *PeriodicTrafficResetJob) updateLastResetTime(inbound *model.Inbound, resetTime time.Time) {
|
|
j.mu.Lock()
|
|
defer j.mu.Unlock()
|
|
j.lastResetTimes[j.getResetKey(inbound)] = resetTime
|
|
}
|