periodic_traffic_reset_job.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package job
  2. import (
  3. "time"
  4. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  5. "github.com/mhsanaei/3x-ui/v3/internal/web/service"
  6. )
  7. // Period represents the time period for traffic resets.
  8. type Period string
  9. // PeriodicTrafficResetJob resets traffic statistics for inbounds based on their configured reset period.
  10. type PeriodicTrafficResetJob struct {
  11. inboundService service.InboundService
  12. clientService service.ClientService
  13. period Period
  14. location *time.Location
  15. }
  16. // NewPeriodicTrafficResetJob creates a new periodic traffic reset job for the specified period.
  17. func NewPeriodicTrafficResetJob(period Period, location *time.Location) *PeriodicTrafficResetJob {
  18. return &PeriodicTrafficResetJob{
  19. period: period,
  20. location: location,
  21. }
  22. }
  23. func monthlyResetDue(resetDay int, now time.Time) bool {
  24. if resetDay < 1 {
  25. resetDay = 1
  26. }
  27. lastDay := time.Date(now.Year(), now.Month()+1, 0, 0, 0, 0, 0, now.Location()).Day()
  28. return now.Day() == min(resetDay, lastDay)
  29. }
  30. // Run resets traffic statistics for all inbounds that match the configured reset period.
  31. func (j *PeriodicTrafficResetJob) Run() {
  32. inbounds, err := j.inboundService.GetInboundsByTrafficReset(string(j.period))
  33. if err != nil {
  34. logger.Warning("Failed to get inbounds for traffic reset:", err)
  35. return
  36. }
  37. if j.period == "monthly" {
  38. now := time.Now().In(j.location)
  39. due := inbounds[:0]
  40. for _, inbound := range inbounds {
  41. if monthlyResetDue(inbound.TrafficResetDay, now) {
  42. due = append(due, inbound)
  43. }
  44. }
  45. inbounds = due
  46. }
  47. if len(inbounds) == 0 {
  48. return
  49. }
  50. logger.Infof("Running periodic traffic reset job for period: %s (%d matching inbounds)", j.period, len(inbounds))
  51. resetCount := 0
  52. for _, inbound := range inbounds {
  53. resetInboundErr := j.inboundService.ResetInboundTraffic(inbound.Id)
  54. if resetInboundErr != nil {
  55. logger.Warning("Failed to reset traffic for inbound", inbound.Id, ":", resetInboundErr)
  56. }
  57. resetClientErr := j.clientService.ResetAllClientTraffics(&j.inboundService, inbound.Id)
  58. if resetClientErr != nil {
  59. logger.Warning("Failed to reset traffic for all users of inbound", inbound.Id, ":", resetClientErr)
  60. }
  61. if resetInboundErr == nil && resetClientErr == nil {
  62. resetCount++
  63. }
  64. }
  65. if resetCount > 0 {
  66. logger.Infof("Periodic traffic reset completed: %d inbounds reset", resetCount)
  67. }
  68. }