[feat] delayStart and autoReset #718

This commit is contained in:
Alireza Ahmadi
2026-03-08 23:18:08 +01:00
parent f4e08c8ae3
commit 6ba547331e
4 changed files with 115 additions and 12 deletions
+8
View File
@@ -35,6 +35,14 @@ type Client struct {
Up int64 `json:"up" form:"up"` Up int64 `json:"up" form:"up"`
Desc string `json:"desc" form:"desc"` Desc string `json:"desc" form:"desc"`
Group string `json:"group" form:"group"` Group string `json:"group" form:"group"`
// Delay start and periodic reset
DelayStart bool `json:"delayStart" form:"delayStart" gorm:"default:false;not null"`
AutoReset bool `json:"autoReset" form:"autoReset" gorm:"default:false;not null"`
ResetDays int `json:"resetDays" form:"resetDays" gorm:"default:0;not null"`
NextReset int64 `json:"nextReset" form:"nextReset" gorm:"default:0;not null"`
TotalUp int64 `json:"totalUp" form:"totalUp" gorm:"default:0;not null"`
TotalDown int64 `json:"totalDown" form:"totalDown" gorm:"default:0;not null"`
} }
type Stats struct { type Stats struct {
+100 -5
View File
@@ -38,7 +38,9 @@ func (s *ClientService) getById(id string) (*[]model.Client, error) {
func (s *ClientService) GetAll() (*[]model.Client, error) { func (s *ClientService) GetAll() (*[]model.Client, error) {
db := database.GetDB() db := database.GetDB()
var clients []model.Client var clients []model.Client
err := db.Model(model.Client{}).Select("`id`, `enable`, `name`, `desc`, `group`, `inbounds`, `up`, `down`, `volume`, `expiry`").Scan(&clients).Error err := db.Model(model.Client{}).
Select("`id`, `enable`, `name`, `desc`, `group`, `inbounds`, `up`, `down`, `volume`, `expiry`").
Scan(&clients).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -369,24 +371,34 @@ func (s *ClientService) DepleteClients() ([]uint, error) {
var users []string var users []string
var inboundIds []uint var inboundIds []uint
now := time.Now().Unix() dt := time.Now().Unix()
db := database.GetDB() db := database.GetDB()
tx := db.Begin() tx := db.Begin()
defer func() { defer func() {
if err == nil { if err == nil {
tx.Commit() tx.Commit()
_, err1 := db.Raw("PRAGMA wal_checkpoint(FULL)").Rows()
if err1 != nil {
logger.Error("Error checkpointing WAL: ", err1.Error())
}
} else { } else {
tx.Rollback() tx.Rollback()
} }
}() }()
err = tx.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", now).Scan(&clients).Error // Reset clients
inboundIds, err = s.ResetClients(tx, dt)
if err != nil {
return nil, err
}
// Deplete clients
err = tx.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", dt).Scan(&clients).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
dt := time.Now().Unix()
for _, client := range clients { for _, client := range clients {
logger.Debug("Client ", client.Name, " is going to be disabled") logger.Debug("Client ", client.Name, " is going to be disabled")
users = append(users, client.Name) users = append(users, client.Name)
@@ -405,7 +417,7 @@ func (s *ClientService) DepleteClients() ([]uint, error) {
// Save changes // Save changes
if len(changes) > 0 { if len(changes) > 0 {
err = tx.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", now).Update("enable", false).Error err = tx.Model(model.Client{}).Where("enable = true AND ((volume >0 AND up+down > volume) OR (expiry > 0 AND expiry < ?))", dt).Update("enable", false).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -419,6 +431,89 @@ func (s *ClientService) DepleteClients() ([]uint, error) {
return inboundIds, nil return inboundIds, nil
} }
func (s *ClientService) ResetClients(tx *gorm.DB, dt int64) ([]uint, error) {
var err error
var resetClients, allClients []*model.Client
var changes []model.Changes
var inboundIds []uint
// Set delay start without periodic reset
err = tx.Model(model.Client{}).
Where("enable = true AND delay_start = true AND auto_reset = false AND (Up + Down) > 0").Find(&resetClients).Error
if err != nil {
return nil, err
}
for _, client := range resetClients {
client.Expiry = dt + (int64(client.ResetDays) * 86400)
client.DelayStart = false
changes = append(changes, model.Changes{
DateTime: dt,
Actor: "ResetJob",
Key: "clients",
Action: "reset",
Obj: json.RawMessage("\"" + client.Name + "\""),
})
}
allClients = append(allClients, resetClients...)
// Set delay start with periodic reset
err = tx.Model(model.Client{}).
Where("enable = true AND delay_start = true AND auto_reset = true AND (Up + Down) > 0").Find(&resetClients).Error
if err != nil {
return nil, err
}
for _, client := range resetClients {
client.NextReset = dt + (int64(client.ResetDays) * 86400)
client.DelayStart = false
changes = append(changes, model.Changes{
DateTime: dt,
Actor: "ResetJob",
Key: "clients",
Action: "reset",
Obj: json.RawMessage("\"" + client.Name + "\""),
})
}
allClients = append(allClients, resetClients...)
// Set periodic reset
err = tx.Model(model.Client{}).
Where("delay_start = false AND auto_reset = true AND next_reset < ?", dt).Find(&resetClients).Error
if err != nil {
return nil, err
}
for _, client := range resetClients {
client.NextReset = dt + (int64(client.ResetDays) * 86400)
client.TotalUp += client.Up
client.TotalDown += client.Down
client.Up = 0
client.Down = 0
if !client.Enable {
client.Enable = true
var clientInboundIds []uint
json.Unmarshal(client.Inbounds, &clientInboundIds)
inboundIds = common.UnionUintArray(inboundIds, clientInboundIds)
}
}
allClients = append(allClients, resetClients...)
// Save clients
if len(allClients) > 0 {
err = tx.Save(allClients).Error
if err != nil {
return nil, err
}
}
// Save changes
if len(changes) > 0 {
err = tx.Model(model.Changes{}).Create(&changes).Error
if err != nil {
return nil, err
}
LastUpdate = dt
}
return inboundIds, nil
}
func (s *ClientService) findInboundsChanges(tx *gorm.DB, client *model.Client, fillOmitted bool) ([]uint, error) { func (s *ClientService) findInboundsChanges(tx *gorm.DB, client *model.Client, fillOmitted bool) ([]uint, error) {
var err error var err error
var oldClient model.Client var oldClient model.Client
+5 -5
View File
@@ -14,12 +14,12 @@ import (
) )
var ( var (
LastUpdate int64 LastUpdate int64
corePtr *core.Core corePtr *core.Core
startCoreMu sync.Mutex startCoreMu sync.Mutex
startCoreInProgress bool startCoreInProgress bool
lastStartFailTime time.Time lastStartFailTime time.Time
startCooldown = 15 * time.Second startCooldown = 15 * time.Second
) )
type ConfigService struct { type ConfigService struct {
+2 -2
View File
@@ -268,8 +268,8 @@ func (s *ServerService) GetDatabaseInfo() map[string]int64 {
db.Model(&model.Outbound{}).Count(&outboundsCount) db.Model(&model.Outbound{}).Count(&outboundsCount)
db.Model(&model.Service{}).Count(&servicesCount) db.Model(&model.Service{}).Count(&servicesCount)
db.Model(&model.Endpoint{}).Count(&endpointsCount) db.Model(&model.Endpoint{}).Count(&endpointsCount)
db.Model(&model.Client{}).Select("COALESCE(SUM(up),0)").Scan(&clientUp) db.Model(&model.Client{}).Select("COALESCE(SUM(up+total_up),0)").Scan(&clientUp)
db.Model(&model.Client{}).Select("COALESCE(SUM(down),0)").Scan(&clientDown) db.Model(&model.Client{}).Select("COALESCE(SUM(down+total_down),0)").Scan(&clientDown)
info["clients"] = clientsCount info["clients"] = clientsCount
info["inbounds"] = inboundsCount info["inbounds"] = inboundsCount