From c418e992ca551cc3d82745e6bf35a73b8ebf394e Mon Sep 17 00:00:00 2001 From: Vadim Iskuchekov Date: Tue, 9 Sep 2025 17:37:06 +0000 Subject: [PATCH] refactor: rename periodicTrafficReset to trafficReset and add lastTrafficResetTime field --- database/model/model.go | 35 +++++++++--------- web/service/inbound.go | 80 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/database/model/model.go b/database/model/model.go index a34dc097..4e243a82 100644 --- a/database/model/model.go +++ b/database/model/model.go @@ -36,7 +36,8 @@ type Inbound struct { Remark string `json:"remark" form:"remark"` Enable bool `json:"enable" form:"enable"` ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` - PeriodicTrafficReset string `json:"periodicTrafficReset" form:"periodicTrafficReset" gorm:"default:never"` + TrafficReset string `json:"trafficReset" form:"trafficReset" gorm:"default:never"` + LastTrafficResetTime int64 `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"` ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"` // config part @@ -91,19 +92,21 @@ type Setting struct { } type Client struct { - ID string `json:"id"` - Security string `json:"security"` - Password string `json:"password"` - Flow string `json:"flow"` - Email string `json:"email"` - LimitIP int `json:"limitIp"` - TotalGB int64 `json:"totalGB" form:"totalGB"` - ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` - Enable bool `json:"enable" form:"enable"` - TgID int64 `json:"tgId" form:"tgId"` - SubID string `json:"subId" form:"subId"` - Comment string `json:"comment" form:"comment"` - Reset int `json:"reset" form:"reset"` - CreatedAt int64 `json:"created_at,omitempty"` - UpdatedAt int64 `json:"updated_at,omitempty"` + ID string `json:"id"` + Security string `json:"security"` + Password string `json:"password"` + Flow string `json:"flow"` + Email string `json:"email"` + LimitIP int `json:"limitIp"` + TotalGB int64 `json:"totalGB" form:"totalGB"` + ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` + TrafficReset string `json:"trafficReset" form:"trafficReset" gorm:"default:never"` + LastTrafficResetTime int64 `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"` + Enable bool `json:"enable" form:"enable"` + TgID int64 `json:"tgId" form:"tgId"` + SubID string `json:"subId" form:"subId"` + Comment string `json:"comment" form:"comment"` + Reset int `json:"reset" form:"reset"` + CreatedAt int64 `json:"created_at,omitempty"` + UpdatedAt int64 `json:"updated_at,omitempty"` } diff --git a/web/service/inbound.go b/web/service/inbound.go index 1be873ac..ca5d99be 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -41,16 +41,46 @@ func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) { return inbounds, nil } -func (s *InboundService) GetInboundsByPeriodicTrafficReset(period string) ([]*model.Inbound, error) { +func (s *InboundService) GetInboundsByTrafficReset(period string) ([]*model.Inbound, error) { db := database.GetDB() var inbounds []*model.Inbound - err := db.Model(model.Inbound{}).Where("periodic_traffic_reset = ?", period).Find(&inbounds).Error + err := db.Model(model.Inbound{}).Where("traffic_reset = ?", period).Find(&inbounds).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } return inbounds, nil } +func (s *InboundService) GetClientsByTrafficReset(period string) ([]model.Client, error) { + db := database.GetDB() + var inbounds []*model.Inbound + + // Get all inbounds first + err := db.Model(model.Inbound{}).Find(&inbounds).Error + if err != nil { + return nil, err + } + + var clientsWithReset []model.Client + + // Parse each inbound's settings to find clients with matching traffic reset period + for _, inbound := range inbounds { + clients, err := s.GetClients(inbound) + if err != nil { + logger.Warning("Failed to get clients for inbound", inbound.Id, ":", err) + continue + } + + for _, client := range clients { + if client.TrafficReset == period { + clientsWithReset = append(clientsWithReset, client) + } + } + } + + return clientsWithReset, nil +} + func (s *InboundService) checkPortExist(listen string, port int, ignoreId int) (bool, error) { db := database.GetDB() if listen == "" || listen == "0.0.0.0" || listen == "::" || listen == "::0" { @@ -407,7 +437,7 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, oldInbound.Remark = inbound.Remark oldInbound.Enable = inbound.Enable oldInbound.ExpiryTime = inbound.ExpiryTime - oldInbound.PeriodicTrafficReset = inbound.PeriodicTrafficReset + oldInbound.TrafficReset = inbound.TrafficReset oldInbound.Listen = inbound.Listen oldInbound.Port = inbound.Port oldInbound.Protocol = inbound.Protocol @@ -697,6 +727,7 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool, } func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId string) (bool, error) { + // TODO: check if TrafficReset field are updating clients, err := s.GetClients(data) if err != nil { return false, err @@ -1682,6 +1713,7 @@ func (s *InboundService) ResetClientTrafficLimitByEmail(clientEmail string, tota func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error { db := database.GetDB() + // Reset traffic stats in ClientTraffic table result := db.Model(xray.ClientTraffic{}). Where("email = ?", clientEmail). Updates(map[string]any{"enable": true, "up": 0, "down": 0}) @@ -1690,6 +1722,48 @@ func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error { if err != nil { return err } + + // Update lastTrafficResetTime in client settings + _, inbound, err := s.GetClientInboundByEmail(clientEmail) + if err != nil { + logger.Warning("Failed to get inbound for client", clientEmail, ":", err) + return nil // Don't fail the reset if we can't update the timestamp + } + + if inbound != nil { + var settings map[string]any + err = json.Unmarshal([]byte(inbound.Settings), &settings) + if err != nil { + logger.Warning("Failed to parse inbound settings:", err) + return nil + } + + clientsSettings := settings["clients"].([]any) + now := time.Now().Unix() * 1000 + + for client_index := range clientsSettings { + c := clientsSettings[client_index].(map[string]any) + if c["email"] == clientEmail { + c["lastTrafficResetTime"] = now + c["updated_at"] = now + break + } + } + + settings["clients"] = clientsSettings + modifiedSettings, err := json.MarshalIndent(settings, "", " ") + if err != nil { + logger.Warning("Failed to marshal inbound settings:", err) + return nil + } + + inbound.Settings = string(modifiedSettings) + err = db.Save(inbound).Error + if err != nil { + logger.Warning("Failed to save inbound with updated client settings:", err) + } + } + return nil }