From 234056072da3048acf1dcbfa83ad8b2a2425f926 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Sun, 8 Feb 2026 10:42:49 +0800 Subject: [PATCH] refactor(management): streamline control panel management and implement sync throttling --- internal/api/server.go | 4 --- internal/managementasset/updater.go | 47 +++++++++++------------------ 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/internal/api/server.go b/internal/api/server.go index 5e194c56..e1e7a14d 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -952,10 +952,6 @@ func (s *Server) UpdateClients(cfg *config.Config) { s.handlers.UpdateClients(&cfg.SDKConfig) - if !cfg.RemoteManagement.DisableControlPanel { - staticDir := managementasset.StaticDir(s.configFilePath) - go managementasset.EnsureLatestManagementHTML(context.Background(), staticDir, cfg.ProxyURL, cfg.RemoteManagement.PanelGitHubRepository) - } if s.mgmt != nil { s.mgmt.SetConfig(cfg) s.mgmt.SetAuthManager(s.handlers.AuthManager) diff --git a/internal/managementasset/updater.go b/internal/managementasset/updater.go index c941da02..2fbaab12 100644 --- a/internal/managementasset/updater.go +++ b/internal/managementasset/updater.go @@ -28,6 +28,7 @@ const ( defaultManagementFallbackURL = "https://cpamc.router-for.me/" managementAssetName = "management.html" httpUserAgent = "CLIProxyAPI-management-updater" + managementSyncMinInterval = 30 * time.Second updateCheckInterval = 3 * time.Hour ) @@ -37,9 +38,7 @@ const ManagementFileName = managementAssetName var ( lastUpdateCheckMu sync.Mutex lastUpdateCheckTime time.Time - currentConfigPtr atomic.Pointer[config.Config] - disableControlPanel atomic.Bool schedulerOnce sync.Once schedulerConfigPath atomic.Value ) @@ -50,16 +49,7 @@ func SetCurrentConfig(cfg *config.Config) { currentConfigPtr.Store(nil) return } - - prevDisabled := disableControlPanel.Load() currentConfigPtr.Store(cfg) - disableControlPanel.Store(cfg.RemoteManagement.DisableControlPanel) - - if prevDisabled && !cfg.RemoteManagement.DisableControlPanel { - lastUpdateCheckMu.Lock() - lastUpdateCheckTime = time.Time{} - lastUpdateCheckMu.Unlock() - } } // StartAutoUpdater launches a background goroutine that periodically ensures the management asset is up to date. @@ -92,7 +82,7 @@ func runAutoUpdater(ctx context.Context) { log.Debug("management asset auto-updater skipped: config not yet available") return } - if disableControlPanel.Load() { + if cfg.RemoteManagement.DisableControlPanel { log.Debug("management asset auto-updater skipped: control panel disabled") return } @@ -182,23 +172,32 @@ 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, panelRepository string) { if ctx == nil { ctx = context.Background() } - if disableControlPanel.Load() { - log.Debug("management asset sync skipped: control panel disabled by configuration") - return - } - staticDir = strings.TrimSpace(staticDir) if staticDir == "" { log.Debug("management asset sync skipped: empty static directory") return } + lastUpdateCheckMu.Lock() + now := time.Now() + timeSinceLastAttempt := now.Sub(lastUpdateCheckTime) + if !lastUpdateCheckTime.IsZero() && timeSinceLastAttempt < managementSyncMinInterval { + lastUpdateCheckMu.Unlock() + log.Debugf( + "management asset sync skipped by throttle: last attempt %v ago (interval %v)", + timeSinceLastAttempt.Round(time.Second), + managementSyncMinInterval, + ) + return + } + lastUpdateCheckTime = now + lastUpdateCheckMu.Unlock() + localPath := filepath.Join(staticDir, managementAssetName) localFileMissing := false if _, errStat := os.Stat(localPath); errStat != nil { @@ -209,18 +208,6 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL } } - // 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 errMkdirAll := os.MkdirAll(staticDir, 0o755); errMkdirAll != nil { log.WithError(errMkdirAll).Warn("failed to prepare static directory for management asset") return