mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 20:30:51 +08:00
refactor(management): streamline control panel management and implement sync throttling
This commit is contained in:
@@ -952,10 +952,6 @@ func (s *Server) UpdateClients(cfg *config.Config) {
|
|||||||
|
|
||||||
s.handlers.UpdateClients(&cfg.SDKConfig)
|
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 {
|
if s.mgmt != nil {
|
||||||
s.mgmt.SetConfig(cfg)
|
s.mgmt.SetConfig(cfg)
|
||||||
s.mgmt.SetAuthManager(s.handlers.AuthManager)
|
s.mgmt.SetAuthManager(s.handlers.AuthManager)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const (
|
|||||||
defaultManagementFallbackURL = "https://cpamc.router-for.me/"
|
defaultManagementFallbackURL = "https://cpamc.router-for.me/"
|
||||||
managementAssetName = "management.html"
|
managementAssetName = "management.html"
|
||||||
httpUserAgent = "CLIProxyAPI-management-updater"
|
httpUserAgent = "CLIProxyAPI-management-updater"
|
||||||
|
managementSyncMinInterval = 30 * time.Second
|
||||||
updateCheckInterval = 3 * time.Hour
|
updateCheckInterval = 3 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,9 +38,7 @@ const ManagementFileName = managementAssetName
|
|||||||
var (
|
var (
|
||||||
lastUpdateCheckMu sync.Mutex
|
lastUpdateCheckMu sync.Mutex
|
||||||
lastUpdateCheckTime time.Time
|
lastUpdateCheckTime time.Time
|
||||||
|
|
||||||
currentConfigPtr atomic.Pointer[config.Config]
|
currentConfigPtr atomic.Pointer[config.Config]
|
||||||
disableControlPanel atomic.Bool
|
|
||||||
schedulerOnce sync.Once
|
schedulerOnce sync.Once
|
||||||
schedulerConfigPath atomic.Value
|
schedulerConfigPath atomic.Value
|
||||||
)
|
)
|
||||||
@@ -50,16 +49,7 @@ func SetCurrentConfig(cfg *config.Config) {
|
|||||||
currentConfigPtr.Store(nil)
|
currentConfigPtr.Store(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prevDisabled := disableControlPanel.Load()
|
|
||||||
currentConfigPtr.Store(cfg)
|
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.
|
// 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")
|
log.Debug("management asset auto-updater skipped: config not yet available")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if disableControlPanel.Load() {
|
if cfg.RemoteManagement.DisableControlPanel {
|
||||||
log.Debug("management asset auto-updater skipped: control panel disabled")
|
log.Debug("management asset auto-updater skipped: control panel disabled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -182,23 +172,32 @@ func FilePath(configFilePath string) string {
|
|||||||
|
|
||||||
// EnsureLatestManagementHTML checks the latest management.html asset and updates the local copy when needed.
|
// 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.
|
// 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) {
|
func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL string, panelRepository string) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
}
|
}
|
||||||
|
|
||||||
if disableControlPanel.Load() {
|
|
||||||
log.Debug("management asset sync skipped: control panel disabled by configuration")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
staticDir = strings.TrimSpace(staticDir)
|
staticDir = strings.TrimSpace(staticDir)
|
||||||
if staticDir == "" {
|
if staticDir == "" {
|
||||||
log.Debug("management asset sync skipped: empty static directory")
|
log.Debug("management asset sync skipped: empty static directory")
|
||||||
return
|
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)
|
localPath := filepath.Join(staticDir, managementAssetName)
|
||||||
localFileMissing := false
|
localFileMissing := false
|
||||||
if _, errStat := os.Stat(localPath); errStat != nil {
|
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 {
|
if errMkdirAll := os.MkdirAll(staticDir, 0o755); errMkdirAll != nil {
|
||||||
log.WithError(errMkdirAll).Warn("failed to prepare static directory for management asset")
|
log.WithError(errMkdirAll).Warn("failed to prepare static directory for management asset")
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user