Skip to content

Commit 67f5538

Browse files
committed
feat: implement management asset configuration and auto-updater
1 parent 2904431 commit 67f5538

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

cmd/server/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/router-for-me/CLIProxyAPI/v6/internal/cmd"
2121
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
2222
"github.com/router-for-me/CLIProxyAPI/v6/internal/logging"
23+
"github.com/router-for-me/CLIProxyAPI/v6/internal/managementasset"
2324
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
2425
"github.com/router-for-me/CLIProxyAPI/v6/internal/store"
2526
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/translator"
@@ -391,6 +392,7 @@ func main() {
391392
} else {
392393
cfg.AuthDir = resolvedAuthDir
393394
}
395+
managementasset.SetCurrentConfig(cfg)
394396

395397
// Create login options to be used in authentication flows.
396398
options := &cmd.LoginOptions{
@@ -434,6 +436,7 @@ func main() {
434436
return
435437
}
436438
// Start the main proxy service
439+
managementasset.StartAutoUpdater(context.Background(), configFilePath)
437440
cmd.StartService(cfg, configFilePath, password)
438441
}
439442
}

internal/api/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
232232
// Save initial YAML snapshot
233233
s.oldConfigYaml, _ = yaml.Marshal(cfg)
234234
s.applyAccessConfig(nil, cfg)
235+
managementasset.SetCurrentConfig(cfg)
235236
// Initialize management handler
236237
s.mgmt = managementHandlers.NewHandler(cfg, configFilePath, authManager)
237238
if optionState.localPassword != "" {
@@ -759,6 +760,7 @@ func (s *Server) UpdateClients(cfg *config.Config) {
759760

760761
s.applyAccessConfig(oldCfg, cfg)
761762
s.cfg = cfg
763+
managementasset.SetCurrentConfig(cfg)
762764
// Save YAML snapshot for next comparison
763765
s.oldConfigYaml, _ = yaml.Marshal(cfg)
764766
s.handlers.UpdateClients(&cfg.SDKConfig)

internal/managementasset/updater.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ import (
1313
"path/filepath"
1414
"strings"
1515
"sync"
16+
"sync/atomic"
1617
"time"
1718

19+
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
1820
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
1921
sdkconfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
2022
log "github.com/sirupsen/logrus"
@@ -33,8 +35,83 @@ const ManagementFileName = managementAssetName
3335
var (
3436
lastUpdateCheckMu sync.Mutex
3537
lastUpdateCheckTime time.Time
38+
39+
currentConfigPtr atomic.Pointer[config.Config]
40+
disableControlPanel atomic.Bool
41+
schedulerOnce sync.Once
42+
schedulerConfigPath atomic.Value
3643
)
3744

45+
// SetCurrentConfig stores the latest configuration snapshot for management asset decisions.
46+
func SetCurrentConfig(cfg *config.Config) {
47+
if cfg == nil {
48+
currentConfigPtr.Store(nil)
49+
return
50+
}
51+
52+
prevDisabled := disableControlPanel.Load()
53+
currentConfigPtr.Store(cfg)
54+
disableControlPanel.Store(cfg.RemoteManagement.DisableControlPanel)
55+
56+
if prevDisabled && !cfg.RemoteManagement.DisableControlPanel {
57+
lastUpdateCheckMu.Lock()
58+
lastUpdateCheckTime = time.Time{}
59+
lastUpdateCheckMu.Unlock()
60+
}
61+
}
62+
63+
// StartAutoUpdater launches a background goroutine that periodically ensures the management asset is up to date.
64+
// It respects the disable-control-panel flag on every iteration and supports hot-reloaded configurations.
65+
func StartAutoUpdater(ctx context.Context, configFilePath string) {
66+
configFilePath = strings.TrimSpace(configFilePath)
67+
if configFilePath == "" {
68+
log.Debug("management asset auto-updater skipped: empty config path")
69+
return
70+
}
71+
72+
schedulerConfigPath.Store(configFilePath)
73+
74+
schedulerOnce.Do(func() {
75+
go runAutoUpdater(ctx)
76+
})
77+
}
78+
79+
func runAutoUpdater(ctx context.Context) {
80+
if ctx == nil {
81+
ctx = context.Background()
82+
}
83+
84+
ticker := time.NewTicker(updateCheckInterval)
85+
defer ticker.Stop()
86+
87+
runOnce := func() {
88+
cfg := currentConfigPtr.Load()
89+
if cfg == nil {
90+
log.Debug("management asset auto-updater skipped: config not yet available")
91+
return
92+
}
93+
if disableControlPanel.Load() {
94+
log.Debug("management asset auto-updater skipped: control panel disabled")
95+
return
96+
}
97+
98+
configPath, _ := schedulerConfigPath.Load().(string)
99+
staticDir := StaticDir(configPath)
100+
EnsureLatestManagementHTML(ctx, staticDir, cfg.ProxyURL)
101+
}
102+
103+
runOnce()
104+
105+
for {
106+
select {
107+
case <-ctx.Done():
108+
return
109+
case <-ticker.C:
110+
runOnce()
111+
}
112+
}
113+
}
114+
38115
func newHTTPClient(proxyURL string) *http.Client {
39116
client := &http.Client{Timeout: 15 * time.Second}
40117

@@ -109,6 +186,11 @@ func EnsureLatestManagementHTML(ctx context.Context, staticDir string, proxyURL
109186
ctx = context.Background()
110187
}
111188

189+
if disableControlPanel.Load() {
190+
log.Debug("management asset sync skipped: control panel disabled by configuration")
191+
return
192+
}
193+
112194
staticDir = strings.TrimSpace(staticDir)
113195
if staticDir == "" {
114196
log.Debug("management asset sync skipped: empty static directory")

0 commit comments

Comments
 (0)