mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-16 01:26:07 +00:00
feat(mtproto): enforce per-client quota & expiry via mtg-multi limits
Map each mtproto client's totalGB and expiryTime onto mtg-multi's new
[secret-limits] (quota/expires): emit them into the generated config and
hot-apply through PUT /secrets so live connections survive. Quota is
written as an exact "<n>B" byte count that round-trips through both the
config and API parsers without the precision loss of a base-2 unit.
The sidecar's quota counter is not pruned when a secret is dropped, so a
panel-side traffic reset re-pushes the client's secret and then calls
POST /secrets/{name}/reset-quota (wired into every reset path) so a
renewed client is not immediately re-blocked.
Resolve the mtg-multi binary from the fork's latest release tag in
DockerInit.sh and release.yml instead of a hardcoded version pin, so the
panel no longer needs a manual bump per fork release.
This commit is contained in:
@@ -122,9 +122,13 @@ func (s *ClientService) BulkResetTraffic(inboundSvc *InboundService, emails []st
|
||||
}
|
||||
|
||||
func (s *ClientService) ResetAllClientTraffics(inboundSvc *InboundService, id int) error {
|
||||
return submitTrafficWrite(func() error {
|
||||
err := submitTrafficWrite(func() error {
|
||||
return s.resetAllClientTrafficsLocked(id)
|
||||
})
|
||||
if err == nil {
|
||||
inboundSvc.resetAllMtprotoQuotas()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ClientService) resetAllClientTrafficsLocked(id int) error {
|
||||
|
||||
@@ -103,3 +103,55 @@ func (s *InboundService) applyLocalMtproto(inboundId int) {
|
||||
logger.Debug("mtproto: immediate client apply failed for inbound", inboundId, ":", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InboundService) resetMtprotoClientQuota(email string) {
|
||||
mgr := mtproto.GetManager()
|
||||
if !mgr.HasRunning() {
|
||||
return
|
||||
}
|
||||
id, ok := s.localMtprotoInboundIdForEmail(email)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
s.applyLocalMtproto(id)
|
||||
mgr.ResetQuota(email)
|
||||
}
|
||||
|
||||
func (s *InboundService) resetAllMtprotoQuotas() {
|
||||
mgr := mtproto.GetManager()
|
||||
if !mgr.HasRunning() {
|
||||
return
|
||||
}
|
||||
desired, err := s.DesiredMtprotoInstances()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mgr.Reconcile(desired)
|
||||
for _, inst := range desired {
|
||||
for _, sec := range inst.Secrets {
|
||||
mgr.ResetQuota(sec.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InboundService) localMtprotoInboundIdForEmail(email string) (int, bool) {
|
||||
db := database.GetDB()
|
||||
var inbounds []*model.Inbound
|
||||
if err := db.Model(model.Inbound{}).
|
||||
Where("protocol = ? AND node_id IS NULL", model.MTProto).
|
||||
Find(&inbounds).Error; err != nil {
|
||||
return 0, false
|
||||
}
|
||||
for _, ib := range inbounds {
|
||||
inst, ok := mtproto.InstanceFromInbound(ib)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, sec := range inst.Secrets {
|
||||
if sec.Name == email {
|
||||
return ib.Id, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ func (s *InboundService) delClientStatsByEmails(tx *gorm.DB, emails []string) er
|
||||
}
|
||||
|
||||
func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
||||
return submitTrafficWrite(func() error {
|
||||
err := submitTrafficWrite(func() error {
|
||||
return database.GetDB().Transaction(func(tx *gorm.DB) error {
|
||||
if err := adjustGroupBaselinesForRemovedTraffic(tx, []string{clientEmail}); err != nil {
|
||||
return err
|
||||
@@ -525,6 +525,10 @@ func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
||||
return tx.Where("email = ?", clientEmail).Delete(&model.NodeClientTraffic{}).Error
|
||||
})
|
||||
})
|
||||
if err == nil {
|
||||
s.resetMtprotoClientQuota(clientEmail)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (needRestart bool, err error) {
|
||||
@@ -533,6 +537,9 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (needRes
|
||||
needRestart, inner = s.resetClientTrafficLocked(id, clientEmail)
|
||||
return inner
|
||||
})
|
||||
if err == nil {
|
||||
s.resetMtprotoClientQuota(clientEmail)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -646,9 +653,13 @@ func (s *InboundService) resetClientTrafficLocked(id int, clientEmail string) (b
|
||||
}
|
||||
|
||||
func (s *InboundService) ResetAllTraffics() error {
|
||||
return submitTrafficWrite(func() error {
|
||||
err := submitTrafficWrite(func() error {
|
||||
return s.resetAllTrafficsLocked()
|
||||
})
|
||||
if err == nil {
|
||||
s.resetAllMtprotoQuotas()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *InboundService) resetAllTrafficsLocked() error {
|
||||
|
||||
Reference in New Issue
Block a user