| // Package modules provides a pluggable routing module system for extending | |
| // the API server with optional features without modifying core routing logic. | |
| package modules | |
| import ( | |
| "fmt" | |
| "github.com/gin-gonic/gin" | |
| "github.com/router-for-me/CLIProxyAPI/v6/internal/config" | |
| "github.com/router-for-me/CLIProxyAPI/v6/sdk/api/handlers" | |
| ) | |
| // Context encapsulates the dependencies exposed to routing modules during | |
| // registration. Modules can use the Gin engine to attach routes, the shared | |
| // BaseAPIHandler for constructing SDK-specific handlers, and the resolved | |
| // authentication middleware for protecting routes that require API keys. | |
| type Context struct { | |
| Engine *gin.Engine | |
| BaseHandler *handlers.BaseAPIHandler | |
| Config *config.Config | |
| AuthMiddleware gin.HandlerFunc | |
| } | |
| // RouteModule represents a pluggable routing module that can register routes | |
| // and handle configuration updates independently of the core server. | |
| // | |
| // DEPRECATED: Use RouteModuleV2 for new modules. This interface is kept for | |
| // backwards compatibility and will be removed in a future version. | |
| type RouteModule interface { | |
| // Name returns a human-readable identifier for the module | |
| Name() string | |
| // Register sets up routes and handlers for this module. | |
| // It receives the Gin engine, base handlers, and current configuration. | |
| // Returns an error if registration fails (errors are logged but don't stop the server). | |
| Register(engine *gin.Engine, baseHandler *handlers.BaseAPIHandler, cfg *config.Config) error | |
| // OnConfigUpdated is called when the configuration is reloaded. | |
| // Modules can respond to configuration changes here. | |
| // Returns an error if the update cannot be applied. | |
| OnConfigUpdated(cfg *config.Config) error | |
| } | |
| // RouteModuleV2 represents a pluggable bundle of routes that can integrate with | |
| // the API server without modifying its core routing logic. Implementations can | |
| // attach routes during Register and react to configuration updates via | |
| // OnConfigUpdated. | |
| // | |
| // This is the preferred interface for new modules. It uses Context for cleaner | |
| // dependency injection and supports idempotent registration. | |
| type RouteModuleV2 interface { | |
| // Name returns a unique identifier for logging and diagnostics. | |
| Name() string | |
| // Register wires the module's routes into the provided Gin engine. Modules | |
| // should treat multiple calls as idempotent and avoid duplicate route | |
| // registration when invoked more than once. | |
| Register(ctx Context) error | |
| // OnConfigUpdated notifies the module when the server configuration changes | |
| // via hot reload. Implementations can refresh cached state or emit warnings. | |
| OnConfigUpdated(cfg *config.Config) error | |
| } | |
| // RegisterModule is a helper that registers a module using either the V1 or V2 | |
| // interface. This allows gradual migration from V1 to V2 without breaking | |
| // existing modules. | |
| // | |
| // Example usage: | |
| // | |
| // ctx := modules.Context{ | |
| // Engine: engine, | |
| // BaseHandler: baseHandler, | |
| // Config: cfg, | |
| // AuthMiddleware: authMiddleware, | |
| // } | |
| // if err := modules.RegisterModule(ctx, ampModule); err != nil { | |
| // log.Errorf("Failed to register module: %v", err) | |
| // } | |
| func RegisterModule(ctx Context, mod interface{}) error { | |
| // Try V2 interface first (preferred) | |
| if v2, ok := mod.(RouteModuleV2); ok { | |
| return v2.Register(ctx) | |
| } | |
| // Fall back to V1 interface for backwards compatibility | |
| if v1, ok := mod.(RouteModule); ok { | |
| return v1.Register(ctx.Engine, ctx.BaseHandler, ctx.Config) | |
| } | |
| return fmt.Errorf("unsupported module type %T (must implement RouteModule or RouteModuleV2)", mod) | |
| } | |