mirror of
https://gh-proxy.org/https://github.com/klinsmaya/CLIProxyAPI.git
synced 2026-11-11 02:46:47 +08:00
feat(config): improve config reload handling and introduce async management save hook
- Refactored `ConfigReloadHook` to use `reloadConfigFromWatcher` for consistency. - Added async `reloadConfigAfterManagementSaveAsync` to handle post-save operations. - Introduced `ReloadConfigIfChanged` in watcher for manual trigger support. - Enhanced config reload paths to separate auth synthesis from standard updates. - Updated `applyConfigUpdate` logic to allow more granular reload behaviors. Closes: #3235
This commit is contained in:
@@ -411,7 +411,13 @@ func (h *Handler) persistLocked(c *gin.Context) bool {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to save config: %v", err)})
|
||||
return false
|
||||
}
|
||||
snapshot := h.reloadSnapshotConfigLocked()
|
||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
var reqCtx context.Context
|
||||
if c != nil && c.Request != nil {
|
||||
reqCtx = c.Request.Context()
|
||||
}
|
||||
h.reloadConfigAfterManagementSaveAsync(reqCtx, snapshot)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ func (w *Watcher) scheduleConfigReload() {
|
||||
})
|
||||
}
|
||||
|
||||
// ReloadConfigIfChanged runs the same config reload path used by filesystem events.
|
||||
func (w *Watcher) ReloadConfigIfChanged() {
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
w.reloadConfigIfChanged()
|
||||
}
|
||||
|
||||
func (w *Watcher) reloadConfigIfChanged() {
|
||||
data, err := os.ReadFile(w.configPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -289,8 +289,8 @@ func (b *Builder) Build() (*Service, error) {
|
||||
service.serverOptions = append(service.serverOptions,
|
||||
api.WithPostAuthPersistHook(service.runtimeAuthSyncHook()),
|
||||
api.WithPluginHost(pluginHost),
|
||||
api.WithConfigReloadHook(func(ctx context.Context, cfg *config.Config) {
|
||||
service.applyConfigUpdate(cfg)
|
||||
api.WithConfigReloadHook(func(_ context.Context, _ *config.Config) {
|
||||
service.reloadConfigFromWatcher()
|
||||
}),
|
||||
)
|
||||
return service, nil
|
||||
|
||||
+20
-2
@@ -1097,6 +1097,14 @@ func (s *Service) tryRegisterPluginModelsForAuth(ctx context.Context, a *coreaut
|
||||
}
|
||||
|
||||
func (s *Service) applyConfigUpdate(newCfg *config.Config) {
|
||||
s.applyConfigUpdateWithAuthSynthesis(newCfg, true)
|
||||
}
|
||||
|
||||
func (s *Service) applyWatcherConfigUpdate(newCfg *config.Config) {
|
||||
s.applyConfigUpdateWithAuthSynthesis(newCfg, false)
|
||||
}
|
||||
|
||||
func (s *Service) applyConfigUpdateWithAuthSynthesis(newCfg *config.Config, synthesizeConfigAuths bool) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
@@ -1190,10 +1198,19 @@ func (s *Service) applyConfigUpdate(newCfg *config.Config) {
|
||||
auths: auths,
|
||||
})
|
||||
ctx := coreauth.WithSkipPersist(context.Background())
|
||||
s.registerConfigAPIKeyAuths(ctx, newCfg)
|
||||
if synthesizeConfigAuths {
|
||||
s.registerConfigAPIKeyAuths(ctx, newCfg)
|
||||
}
|
||||
s.syncPluginRuntime(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) reloadConfigFromWatcher() bool {
|
||||
if s == nil || s.watcher == nil {
|
||||
return false
|
||||
}
|
||||
return s.watcher.ReloadConfigIfChanged()
|
||||
}
|
||||
|
||||
func (s *Service) registerConfigAPIKeyAuths(ctx context.Context, cfg *config.Config) {
|
||||
if s == nil || s.coreManager == nil || cfg == nil {
|
||||
return
|
||||
@@ -1442,6 +1459,7 @@ func (s *Service) Run(ctx context.Context) error {
|
||||
if errLoad := s.coreManager.Load(ctx); errLoad != nil {
|
||||
log.Warnf("failed to load auth store: %v", errLoad)
|
||||
}
|
||||
s.registerConfigAPIKeyAuths(coreauth.WithSkipPersist(ctx), s.cfg)
|
||||
}
|
||||
|
||||
if !homeEnabled {
|
||||
@@ -1532,7 +1550,7 @@ func (s *Service) Run(ctx context.Context) error {
|
||||
|
||||
if !homeEnabled {
|
||||
var watcherWrapper *WatcherWrapper
|
||||
reloadCallback := func(newCfg *config.Config) { s.applyConfigUpdate(newCfg) }
|
||||
reloadCallback := func(newCfg *config.Config) { s.applyWatcherConfigUpdate(newCfg) }
|
||||
|
||||
watcherWrapper, errCreate := s.watcherFactory(s.configPath, s.cfg.AuthDir, reloadCallback)
|
||||
if errCreate != nil {
|
||||
|
||||
@@ -97,6 +97,7 @@ type WatcherWrapper struct {
|
||||
dispatchRuntimeUpdate func(update watcher.AuthUpdate) bool
|
||||
dispatchPersistedAuth func(update watcher.AuthUpdate) bool
|
||||
setPluginAuthParser func(parser PluginAuthParser)
|
||||
reloadConfigIfChanged func()
|
||||
}
|
||||
|
||||
// Start proxies to the underlying watcher Start implementation.
|
||||
@@ -123,6 +124,15 @@ func (w *WatcherWrapper) SetConfig(cfg *config.Config) {
|
||||
w.setConfig(cfg)
|
||||
}
|
||||
|
||||
// ReloadConfigIfChanged asks the underlying watcher to reload config from disk.
|
||||
func (w *WatcherWrapper) ReloadConfigIfChanged() bool {
|
||||
if w == nil || w.reloadConfigIfChanged == nil {
|
||||
return false
|
||||
}
|
||||
w.reloadConfigIfChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
// SetPluginAuthParser updates the plugin auth parser used by the watcher.
|
||||
func (w *WatcherWrapper) SetPluginAuthParser(parser PluginAuthParser) {
|
||||
if w == nil || w.setPluginAuthParser == nil {
|
||||
|
||||
@@ -37,5 +37,8 @@ func defaultWatcherFactory(configPath, authDir string, reload func(*config.Confi
|
||||
setPluginAuthParser: func(parser PluginAuthParser) {
|
||||
w.SetPluginAuthParser(parser)
|
||||
},
|
||||
reloadConfigIfChanged: func() {
|
||||
w.ReloadConfigIfChanged()
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user