From 57195fa0f5d637191c7e0f5eee61da2eb67aa6cd Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Fri, 10 Oct 2025 04:23:58 +0800 Subject: [PATCH] feat(managementasset): enforce 3-hour rate limit on management asset update checks - Introduced synchronization with `sync.Mutex` to ensure thread safety. - Added logic to skip update checks if the last check was performed within the 3-hour interval. --- internal/managementasset/updater.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/managementasset/updater.go b/internal/managementasset/updater.go index 8c6e7d43..7478564b 100644 --- a/internal/managementasset/updater.go +++ b/internal/managementasset/updater.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "strings" + "sync" "time" "github.com/router-for-me/CLIProxyAPI/v6/internal/util" @@ -23,11 +24,17 @@ const ( managementReleaseURL = "https://api.github.com/repos/router-for-me/Cli-Proxy-API-Management-Center/releases/latest" managementAssetName = "management.html" httpUserAgent = "CLIProxyAPI-management-updater" + updateCheckInterval = 3 * time.Hour ) // ManagementFileName exposes the control panel asset filename. const ManagementFileName = managementAssetName +var ( + lastUpdateCheckMu sync.Mutex + lastUpdateCheckTime time.Time +) + func newHTTPClient(proxyURL string) *http.Client { client := &http.Client{Timeout: 15 * time.Second} @@ -68,6 +75,7 @@ func FilePath(configFilePath string) string { // EnsureLatestManagementHTML checks the latest management.html asset and updates the local copy when needed. // The function is designed to run in a background goroutine and will never panic. +// It enforces a 3-hour rate limit to avoid frequent checks on config/auth file changes. func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL string) { if ctx == nil { ctx = context.Background() @@ -79,6 +87,18 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL return } + // Rate limiting: check only once every 3 hours + lastUpdateCheckMu.Lock() + now := time.Now() + timeSinceLastCheck := now.Sub(lastUpdateCheckTime) + if timeSinceLastCheck < updateCheckInterval { + lastUpdateCheckMu.Unlock() + log.Debugf("management asset update check skipped: last check was %v ago (interval: %v)", timeSinceLastCheck.Round(time.Second), updateCheckInterval) + return + } + lastUpdateCheckTime = now + lastUpdateCheckMu.Unlock() + if err := os.MkdirAll(staticDir, 0o755); err != nil { log.WithError(err).Warn("failed to prepare static directory for management asset") return