package api import ( "context" "path/filepath" "time" "github.com/gin-gonic/gin" "github.com/router-for-me/CLIProxyAPI/v7/internal/config" "github.com/router-for-me/CLIProxyAPI/v7/internal/logging" "github.com/router-for-me/CLIProxyAPI/v7/internal/pluginhost" "github.com/router-for-me/CLIProxyAPI/v7/sdk/api/handlers" "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" ) type serverOptionConfig struct { extraMiddleware []gin.HandlerFunc engineConfigurator func(*gin.Engine) routerConfigurator func(*gin.Engine, *handlers.BaseAPIHandler, *config.Config) requestLoggerFactory func(*config.Config, string) logging.RequestLogger localPassword string keepAliveEnabled bool keepAliveTimeout time.Duration keepAliveOnTimeout func() postAuthHook auth.PostAuthHook postAuthPersistHook auth.PostAuthHook pluginHost *pluginhost.Host configReloadHook func(context.Context, *config.Config) exampleAPIKeySafeMode bool } // ServerOption customises HTTP server construction. type ServerOption func(*serverOptionConfig) func defaultRequestLoggerFactory(cfg *config.Config, configPath string) logging.RequestLogger { configDir := filepath.Dir(configPath) logsDir := logging.ResolveLogDirectory(cfg) logger := logging.NewFileRequestLogger(cfg.RequestLog, logsDir, configDir, cfg.ErrorLogsMaxFiles) logger.SetHomeEnabled(cfg != nil && cfg.Home.Enabled) return logger } func effectiveSDKConfig(cfg *config.Config) *config.SDKConfig { if cfg == nil { return nil } sdkCfg := cfg.SDKConfig sdkCfg.CodexOptimizeMultiAgentV2 = cfg.Codex.OptimizeMultiAgentV2 if cfg.CommercialMode { sdkCfg.RequestLog = false } return &sdkCfg } // WithMiddleware appends additional Gin middleware during server construction. func WithMiddleware(mw ...gin.HandlerFunc) ServerOption { return func(cfg *serverOptionConfig) { cfg.extraMiddleware = append(cfg.extraMiddleware, mw...) } } // WithEngineConfigurator allows callers to mutate the Gin engine prior to middleware setup. func WithEngineConfigurator(fn func(*gin.Engine)) ServerOption { return func(cfg *serverOptionConfig) { cfg.engineConfigurator = fn } } // WithRouterConfigurator appends a callback after default routes are registered. func WithRouterConfigurator(fn func(*gin.Engine, *handlers.BaseAPIHandler, *config.Config)) ServerOption { return func(cfg *serverOptionConfig) { cfg.routerConfigurator = fn } } // WithLocalManagementPassword stores a runtime-only management password accepted for localhost requests. func WithLocalManagementPassword(password string) ServerOption { return func(cfg *serverOptionConfig) { cfg.localPassword = password } } // WithKeepAliveEndpoint enables a keep-alive endpoint with the provided timeout and callback. func WithKeepAliveEndpoint(timeout time.Duration, onTimeout func()) ServerOption { return func(cfg *serverOptionConfig) { if timeout <= 0 || onTimeout == nil { return } cfg.keepAliveEnabled = true cfg.keepAliveTimeout = timeout cfg.keepAliveOnTimeout = onTimeout } } // WithRequestLoggerFactory customises request logger creation. func WithRequestLoggerFactory(factory func(*config.Config, string) logging.RequestLogger) ServerOption { return func(cfg *serverOptionConfig) { cfg.requestLoggerFactory = factory } } // WithPostAuthHook registers a hook to be called after auth record creation. func WithPostAuthHook(hook auth.PostAuthHook) ServerOption { return func(cfg *serverOptionConfig) { cfg.postAuthHook = hook } } // WithPostAuthPersistHook registers a hook to be called after auth persistence. func WithPostAuthPersistHook(hook auth.PostAuthHook) ServerOption { return func(cfg *serverOptionConfig) { cfg.postAuthPersistHook = hook } } // WithPluginHost registers dynamic plugin HTTP adapters with the server. func WithPluginHost(host *pluginhost.Host) ServerOption { return func(cfg *serverOptionConfig) { cfg.pluginHost = host } } // WithConfigReloadHook registers a callback used after management saves config changes. func WithConfigReloadHook(hook func(context.Context, *config.Config)) ServerOption { return func(cfg *serverOptionConfig) { cfg.configReloadHook = hook } } // WithExampleAPIKeySafeMode blocks proxy API endpoints while template API keys remain configured. func WithExampleAPIKeySafeMode() ServerOption { return func(cfg *serverOptionConfig) { cfg.exampleAPIKeySafeMode = true } }