fix(traffic): restore quota-disabled inbounds when their traffic is reset (#6962)

An inbound switched off by its own traffic cap came back on the periodic reset, but the admin per-inbound reset and Reset All Traffic only zeroed the counters. After that nothing could tell it from a hand-disabled inbound, so it stayed off with every client on it. Both admin resets now re-enable the inbounds their cap switched off, using the predicate the periodic job used, now in the service next to disableInvalidInbounds; expired and hand-disabled inbounds stay off.
This commit is contained in:
25f2002654
2026-11-02 20:20:25 +05:30
committed by GitHub
parent 1796352600
commit eae4725d99
9 changed files with 184 additions and 38 deletions
+3 -19
View File
@@ -5,7 +5,6 @@ import (
"sync/atomic"
"time"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
"github.com/mhsanaei/3x-ui/v3/internal/logger"
"github.com/mhsanaei/3x-ui/v3/internal/util/common"
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
@@ -43,13 +42,6 @@ func monthlyResetDue(resetDay int, now time.Time) bool {
return now.Day() == min(resetDay, lastDay)
}
// inboundQuotaDisabled mirrors disableInvalidInbounds: a local inbound its own
// traffic cap switched off, not one that expired or was switched off by hand.
func inboundQuotaDisabled(ib *model.Inbound, nowMs int64) bool {
return !ib.Enable && ib.NodeID == nil && ib.Total > 0 && ib.Up+ib.Down >= ib.Total &&
(ib.ExpiryTime <= 0 || ib.ExpiryTime > nowMs)
}
func forEachResetBounded(n int, reset func(i int)) {
sem := make(chan struct{}, periodicResetConcurrency)
var wg sync.WaitGroup
@@ -96,21 +88,13 @@ func (j *PeriodicTrafficResetJob) resetInboundsOnSchedule() {
var resetCount atomic.Int32
var needRestart atomic.Bool
nowMs := time.Now().UnixMilli()
forEachResetBounded(len(inbounds), func(i int) {
inbound := inbounds[i]
quotaOff := inboundQuotaDisabled(inbound, nowMs)
resetInboundErr := j.inboundService.ResetInboundTraffic(inbound.Id)
nr, resetInboundErr := j.inboundService.ResetInboundTraffic(inbound.Id)
if resetInboundErr != nil {
logger.Warning("Failed to reset traffic for inbound", inbound.Id, ":", resetInboundErr)
} else if quotaOff {
nr, err := j.inboundService.SetInboundEnable(inbound.Id, true)
if err != nil {
logger.Warning("Failed to re-enable inbound", inbound.Id, "after traffic reset:", err)
}
if nr {
needRestart.Store(true)
}
} else if nr {
needRestart.Store(true)
}
nr, resetClientErr := j.clientService.ResetAllClientTraffics(&j.inboundService, inbound.Id)