mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-08 18:56:37 +08:00
Implement per-tunnel traffic quota feature: - Add TunnelQuota model with daily/monthly usage tracking - Integrate quota enforcement into flow accumulation path - Pause forwards and disable tunnel when quota exceeded - Block new forward creation/resume when tunnel quota disabled - Auto-reset daily/monthly windows at 00:05 via maintenance job - Add manual reset API endpoint for admins - Include quota config in tunnel backup/restore - Add frontend UI for quota settings and usage display Entire-Checkpoint: e629b27ca437
This commit is contained in:
@@ -485,6 +485,8 @@ func (h *Handler) tunnelCreate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
typeVal := asInt(req["type"], 1)
|
||||
flow := asInt64(req["flow"], 1)
|
||||
dailyQuotaGB := asInt64(req["dailyQuotaGB"], 0)
|
||||
monthlyQuotaGB := asInt64(req["monthlyQuotaGB"], 0)
|
||||
status := asInt(req["status"], 1)
|
||||
trafficRatio := asFloat(req["trafficRatio"], 1.0)
|
||||
inIP := asString(req["inIp"])
|
||||
@@ -580,6 +582,10 @@ func (h *Handler) tunnelCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
tunnelID := tunnel.ID
|
||||
if err := h.repo.SaveTunnelQuotaConfigTx(tx, tunnelID, dailyQuotaGB, monthlyQuotaGB, now); err != nil {
|
||||
response.WriteJSON(w, response.Err(-2, err.Error()))
|
||||
return
|
||||
}
|
||||
runtimeState.TunnelID = tunnelID
|
||||
var federationBindings []repo.FederationTunnelBinding
|
||||
var federationReleaseRefs []federationRuntimeReleaseRef
|
||||
@@ -691,6 +697,8 @@ func (h *Handler) tunnelUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
typeVal := asInt(req["type"], 1)
|
||||
dailyQuotaGB := asInt64(req["dailyQuotaGB"], 0)
|
||||
monthlyQuotaGB := asInt64(req["monthlyQuotaGB"], 0)
|
||||
ipPreference := asString(req["ipPreference"])
|
||||
localDomain := h.federationLocalDomain()
|
||||
|
||||
@@ -735,6 +743,10 @@ func (h *Handler) tunnelUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
response.WriteJSON(w, response.Err(-2, err.Error()))
|
||||
return
|
||||
}
|
||||
if err := h.repo.SaveTunnelQuotaConfigTx(tx, id, dailyQuotaGB, monthlyQuotaGB, now); err != nil {
|
||||
response.WriteJSON(w, response.Err(-2, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.repo.DeleteChainTunnelsByTunnelTx(tx, id); err != nil {
|
||||
response.WriteJSON(w, response.Err(-2, err.Error()))
|
||||
@@ -1299,6 +1311,10 @@ func (h *Handler) forwardCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
if tunnel.Status != 1 {
|
||||
if reason, quotaErr := h.tunnelQuotaBlockReason(tunnelID, time.Now().UnixMilli()); quotaErr == nil && reason != "" {
|
||||
response.WriteJSON(w, response.ErrDefault(reason))
|
||||
return
|
||||
}
|
||||
response.WriteJSON(w, response.ErrDefault("隧道已禁用,无法创建转发"))
|
||||
return
|
||||
}
|
||||
@@ -1420,6 +1436,10 @@ func (h *Handler) forwardUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
if tunnel.Status != 1 {
|
||||
if reason, quotaErr := h.tunnelQuotaBlockReason(tunnelID, time.Now().UnixMilli()); quotaErr == nil && reason != "" {
|
||||
response.WriteJSON(w, response.ErrDefault(reason))
|
||||
return
|
||||
}
|
||||
response.WriteJSON(w, response.ErrDefault("隧道已禁用,无法更新转发"))
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user