package cliproxy import ( "fmt" "github.com/router-for-me/CLIProxyAPI/v6/internal/api" "github.com/router-for-me/CLIProxyAPI/v6/internal/config" sdkAuth "github.com/router-for-me/CLIProxyAPI/v6/sdk/auth" coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" ) // Builder constructs a Service instance with customizable providers. type Builder struct { cfg *config.Config configPath string tokenProvider TokenClientProvider apiKeyProvider APIKeyClientProvider watcherFactory WatcherFactory hooks Hooks authManager *sdkAuth.Manager coreManager *coreauth.Manager serverOptions []api.ServerOption } // Hooks allows callers to plug into service lifecycle stages. type Hooks struct { OnBeforeStart func(*config.Config) OnAfterStart func(*Service) } // NewBuilder creates a Builder with default dependencies left unset. func NewBuilder() *Builder { return &Builder{} } // WithConfig sets the configuration instance used by the service. func (b *Builder) WithConfig(cfg *config.Config) *Builder { b.cfg = cfg return b } // WithConfigPath sets the absolute configuration file path used for reload watching. func (b *Builder) WithConfigPath(path string) *Builder { b.configPath = path return b } // WithTokenClientProvider overrides the provider responsible for token-backed clients. func (b *Builder) WithTokenClientProvider(provider TokenClientProvider) *Builder { b.tokenProvider = provider return b } // WithAPIKeyClientProvider overrides the provider responsible for API key-backed clients. func (b *Builder) WithAPIKeyClientProvider(provider APIKeyClientProvider) *Builder { b.apiKeyProvider = provider return b } // WithWatcherFactory allows customizing the watcher factory that handles reloads. func (b *Builder) WithWatcherFactory(factory WatcherFactory) *Builder { b.watcherFactory = factory return b } // WithHooks registers lifecycle hooks executed around service startup. func (b *Builder) WithHooks(h Hooks) *Builder { b.hooks = h return b } // WithAuthManager overrides the authentication manager used for token lifecycle operations. func (b *Builder) WithAuthManager(mgr *sdkAuth.Manager) *Builder { b.authManager = mgr return b } // WithCoreAuthManager overrides the runtime auth manager responsible for request execution. func (b *Builder) WithCoreAuthManager(mgr *coreauth.Manager) *Builder { b.coreManager = mgr return b } // WithServerOptions appends server configuration options used during construction. func (b *Builder) WithServerOptions(opts ...api.ServerOption) *Builder { b.serverOptions = append(b.serverOptions, opts...) return b } // Build validates inputs, applies defaults, and returns a ready-to-run service. func (b *Builder) Build() (*Service, error) { if b.cfg == nil { return nil, fmt.Errorf("cliproxy: configuration is required") } if b.configPath == "" { return nil, fmt.Errorf("cliproxy: configuration path is required") } tokenProvider := b.tokenProvider if tokenProvider == nil { tokenProvider = NewFileTokenClientProvider() } apiKeyProvider := b.apiKeyProvider if apiKeyProvider == nil { apiKeyProvider = NewAPIKeyClientProvider() } watcherFactory := b.watcherFactory if watcherFactory == nil { watcherFactory = defaultWatcherFactory } authManager := b.authManager if authManager == nil { authManager = newDefaultAuthManager() } coreManager := b.coreManager if coreManager == nil { coreManager = coreauth.NewManager(coreauth.NewFileStore(b.cfg.AuthDir), nil, nil) } // Attach a default RoundTripper provider so providers can opt-in per-auth transports. coreManager.SetRoundTripperProvider(newDefaultRoundTripperProvider()) service := &Service{ cfg: b.cfg, configPath: b.configPath, tokenProvider: tokenProvider, apiKeyProvider: apiKeyProvider, watcherFactory: watcherFactory, hooks: b.hooks, authManager: authManager, coreManager: coreManager, serverOptions: append([]api.ServerOption(nil), b.serverOptions...), } return service, nil }