From b4a0997564f3d673987de3a2f03247230e4ab0ce Mon Sep 17 00:00:00 2001 From: viettranx Date: Wed, 25 Mar 2026 10:26:11 +0700 Subject: [PATCH] refactor(gateway): consolidate 27 handler fields into routeRegistrar slice Replace 27 individual handler fields with single handlers []routeRegistrar slice. BuildMux() registers all handlers via one loop instead of 27 nil-check blocks. Setter methods now append to slice. Reduces server.go from 735 to 612 LOC (-123). No caller changes, no behavior change. --- internal/gateway/server.go | 259 ++++++++++--------------------------- 1 file changed, 68 insertions(+), 191 deletions(-) diff --git a/internal/gateway/server.go b/internal/gateway/server.go index e9487790..c81b869e 100644 --- a/internal/gateway/server.go +++ b/internal/gateway/server.go @@ -28,6 +28,11 @@ import ( ) // Server is the main gateway server handling WebSocket and HTTP connections. +// routeRegistrar is implemented by all HTTP API handlers that register routes on a mux. +type routeRegistrar interface { + RegisterRoutes(mux *http.ServeMux) +} + type Server struct { cfg *config.Config eventPub bus.EventPublisher @@ -36,39 +41,16 @@ type Server struct { tools *tools.Registry router *MethodRouter + // HTTP API handlers — all implement routeRegistrar. + // Registered via Set*Handler() setters, routes added in BuildMux() via single loop. + handlers []routeRegistrar + + // Non-handler dependencies (don't implement RegisterRoutes) policyEngine *permissions.PolicyEngine pairingService store.PairingStore - agentsHandler *httpapi.AgentsHandler // agent CRUD API - skillsHandler *httpapi.SkillsHandler // skill management API - tracesHandler *httpapi.TracesHandler // LLM trace listing API - wakeHandler *httpapi.WakeHandler // external wake/trigger API - mcpHandler *httpapi.MCPHandler // MCP server management API - channelInstancesHandler *httpapi.ChannelInstancesHandler // channel instance CRUD API - providersHandler *httpapi.ProvidersHandler // provider CRUD API - teamEventsHandler *httpapi.TeamEventsHandler // team event history API - teamAttachmentsHandler *httpapi.TeamAttachmentsHandler // team attachment download API - workspaceUploadHandler *httpapi.WorkspaceUploadHandler // team workspace file upload API - builtinToolsHandler *httpapi.BuiltinToolsHandler // builtin tool management API - pendingMessagesHandler *httpapi.PendingMessagesHandler // pending messages API - secureCLIHandler *httpapi.SecureCLIHandler // secure CLI credential CRUD API - mcpUserCredsHandler *httpapi.MCPUserCredentialsHandler // MCP per-user credentials API - packagesHandler *httpapi.PackagesHandler // runtime package management API - memoryHandler *httpapi.MemoryHandler // memory management API - kgHandler *httpapi.KnowledgeGraphHandler // knowledge graph API - oauthHandler *httpapi.OAuthHandler // OAuth endpoints - filesHandler *httpapi.FilesHandler // workspace file serving - storageHandler *httpapi.StorageHandler // storage file management - mediaUploadHandler *httpapi.MediaUploadHandler // media upload endpoint - mediaServeHandler *httpapi.MediaServeHandler // media serve endpoint - activityHandler *httpapi.ActivityHandler // activity audit log API - systemConfigsHandler *httpapi.SystemConfigsHandler // system configs API - usageHandler *httpapi.UsageHandler // usage analytics API - apiKeysHandler *httpapi.APIKeysHandler // API key management - apiKeyStore store.APIKeyStore // for API key auth lookup - tenantsHandler *httpapi.TenantsHandler // tenant management API - docsHandler *httpapi.DocsHandler // OpenAPI spec + Swagger UI - agentStore store.AgentStore // for context injection in tools_invoke - msgBus *bus.MessageBus // for MCP bridge media delivery + apiKeyStore store.APIKeyStore // for API key auth lookup + agentStore store.AgentStore // for context injection in tools_invoke + msgBus *bus.MessageBus // for MCP bridge media delivery upgrader websocket.Upgrader rateLimiter *RateLimiter @@ -186,138 +168,9 @@ func (s *Server) BuildMux() *http.ServeMux { mux.Handle("/v1/tools/invoke", toolsHandler) } - // Agent CRUD + shares API - if s.agentsHandler != nil { - s.agentsHandler.RegisterRoutes(mux) - } - - // Skill management API - if s.skillsHandler != nil { - s.skillsHandler.RegisterRoutes(mux) - } - - // LLM trace listing API - if s.tracesHandler != nil { - s.tracesHandler.RegisterRoutes(mux) - } - - // External wake/trigger API - if s.wakeHandler != nil { - s.wakeHandler.RegisterRoutes(mux) - } - - // MCP server management API - if s.mcpHandler != nil { - s.mcpHandler.RegisterRoutes(mux) - } - // MCP per-user credentials API - if s.mcpUserCredsHandler != nil { - s.mcpUserCredsHandler.RegisterRoutes(mux) - } - - // Secure CLI credential CRUD API - if s.secureCLIHandler != nil { - s.secureCLIHandler.RegisterRoutes(mux) - } - - // Channel instance CRUD API - if s.channelInstancesHandler != nil { - s.channelInstancesHandler.RegisterRoutes(mux) - } - - // Provider & model CRUD API - if s.providersHandler != nil { - s.providersHandler.RegisterRoutes(mux) - } - - - // Team event history API - if s.teamEventsHandler != nil { - s.teamEventsHandler.RegisterRoutes(mux) - } - - // Team attachment download API - if s.teamAttachmentsHandler != nil { - s.teamAttachmentsHandler.RegisterRoutes(mux) - } - - // Team workspace file upload API - if s.workspaceUploadHandler != nil { - s.workspaceUploadHandler.RegisterRoutes(mux) - } - - // Builtin tool management API - if s.builtinToolsHandler != nil { - s.builtinToolsHandler.RegisterRoutes(mux) - } - - // Pending messages API - if s.pendingMessagesHandler != nil { - s.pendingMessagesHandler.RegisterRoutes(mux) - } - - // Memory management API - if s.memoryHandler != nil { - s.memoryHandler.RegisterRoutes(mux) - } - - // Knowledge graph API - if s.kgHandler != nil { - s.kgHandler.RegisterRoutes(mux) - } - - // Workspace file serving (available in all modes) - if s.filesHandler != nil { - s.filesHandler.RegisterRoutes(mux) - } - - // Storage file management (browse/delete workspace files) - if s.storageHandler != nil { - s.storageHandler.RegisterRoutes(mux) - } - - // Media upload endpoint (available in all modes) - if s.mediaUploadHandler != nil { - s.mediaUploadHandler.RegisterRoutes(mux) - } - - // Media serve endpoint (available in all modes) - if s.mediaServeHandler != nil { - s.mediaServeHandler.RegisterRoutes(mux) - } - - if s.apiKeysHandler != nil { - s.apiKeysHandler.RegisterRoutes(mux) - } - - // Tenant management API - if s.tenantsHandler != nil { - s.tenantsHandler.RegisterRoutes(mux) - } - - if s.activityHandler != nil { - s.activityHandler.RegisterRoutes(mux) - } - if s.systemConfigsHandler != nil { - s.systemConfigsHandler.RegisterRoutes(mux) - } - - if s.usageHandler != nil { - s.usageHandler.RegisterRoutes(mux) - } - - if s.packagesHandler != nil { - s.packagesHandler.RegisterRoutes(mux) - } - - // API documentation (OpenAPI spec + Swagger UI) - if s.docsHandler != nil { - s.docsHandler.RegisterRoutes(mux) - } - - // OAuth endpoints (available in all modes) - if s.oauthHandler != nil { - s.oauthHandler.RegisterRoutes(mux) + // Register all HTTP API handlers (agents, skills, teams, storage, etc.) + for _, h := range s.handlers { + h.RegisterRoutes(mux) } // MCP bridge: expose GoClaw tools to Claude CLI via streamable-http. @@ -496,99 +349,123 @@ func (s *Server) SetPolicyEngine(pe *permissions.PolicyEngine) { s.policyEngine func (s *Server) SetPairingService(ps store.PairingStore) { s.pairingService = ps } // SetAgentsHandler sets the agent CRUD handler. -func (s *Server) SetAgentsHandler(h *httpapi.AgentsHandler) { s.agentsHandler = h } +func (s *Server) SetAgentsHandler(h *httpapi.AgentsHandler) { s.handlers = append(s.handlers, h) } // SetSkillsHandler sets the skill management handler. -func (s *Server) SetSkillsHandler(h *httpapi.SkillsHandler) { s.skillsHandler = h } +func (s *Server) SetSkillsHandler(h *httpapi.SkillsHandler) { s.handlers = append(s.handlers, h) } // SetTracesHandler sets the LLM trace listing handler. -func (s *Server) SetTracesHandler(h *httpapi.TracesHandler) { s.tracesHandler = h } +func (s *Server) SetTracesHandler(h *httpapi.TracesHandler) { s.handlers = append(s.handlers, h) } // SetWakeHandler sets the external wake/trigger handler. -func (s *Server) SetWakeHandler(h *httpapi.WakeHandler) { s.wakeHandler = h } +func (s *Server) SetWakeHandler(h *httpapi.WakeHandler) { s.handlers = append(s.handlers, h) } // SetMCPHandler sets the MCP server management handler. -func (s *Server) SetMCPHandler(h *httpapi.MCPHandler) { s.mcpHandler = h } -func (s *Server) SetMCPUserCredentialsHandler(h *httpapi.MCPUserCredentialsHandler) { s.mcpUserCredsHandler = h } +func (s *Server) SetMCPHandler(h *httpapi.MCPHandler) { s.handlers = append(s.handlers, h) } +func (s *Server) SetMCPUserCredentialsHandler(h *httpapi.MCPUserCredentialsHandler) { + s.handlers = append(s.handlers, h) +} // SetChannelInstancesHandler sets the channel instance CRUD handler. func (s *Server) SetChannelInstancesHandler(h *httpapi.ChannelInstancesHandler) { - s.channelInstancesHandler = h + s.handlers = append(s.handlers, h) } // SetProvidersHandler sets the provider CRUD handler. -func (s *Server) SetProvidersHandler(h *httpapi.ProvidersHandler) { s.providersHandler = h } +func (s *Server) SetProvidersHandler(h *httpapi.ProvidersHandler) { + s.handlers = append(s.handlers, h) +} // SetTeamEventsHandler sets the team event history handler. -func (s *Server) SetTeamEventsHandler(h *httpapi.TeamEventsHandler) { s.teamEventsHandler = h } +func (s *Server) SetTeamEventsHandler(h *httpapi.TeamEventsHandler) { + s.handlers = append(s.handlers, h) +} // SetTeamAttachmentsHandler sets the team attachment download handler. func (s *Server) SetTeamAttachmentsHandler(h *httpapi.TeamAttachmentsHandler) { - s.teamAttachmentsHandler = h + s.handlers = append(s.handlers, h) } // SetWorkspaceUploadHandler sets the team workspace file upload handler. func (s *Server) SetWorkspaceUploadHandler(h *httpapi.WorkspaceUploadHandler) { - s.workspaceUploadHandler = h + s.handlers = append(s.handlers, h) } // SetPendingMessagesHandler sets the pending messages handler. func (s *Server) SetPendingMessagesHandler(h *httpapi.PendingMessagesHandler) { - s.pendingMessagesHandler = h + s.handlers = append(s.handlers, h) } // SetBuiltinToolsHandler sets the builtin tool management handler. func (s *Server) SetBuiltinToolsHandler(h *httpapi.BuiltinToolsHandler) { - s.builtinToolsHandler = h + s.handlers = append(s.handlers, h) } // SetSecureCLIHandler sets the secure CLI credential CRUD handler. -func (s *Server) SetSecureCLIHandler(h *httpapi.SecureCLIHandler) { s.secureCLIHandler = h } +func (s *Server) SetSecureCLIHandler(h *httpapi.SecureCLIHandler) { + s.handlers = append(s.handlers, h) +} // SetPackagesHandler sets the runtime package management handler. -func (s *Server) SetPackagesHandler(h *httpapi.PackagesHandler) { s.packagesHandler = h } +func (s *Server) SetPackagesHandler(h *httpapi.PackagesHandler) { + s.handlers = append(s.handlers, h) +} // SetOAuthHandler sets the OAuth handler (available in all modes). -func (s *Server) SetOAuthHandler(h *httpapi.OAuthHandler) { s.oauthHandler = h } +func (s *Server) SetOAuthHandler(h *httpapi.OAuthHandler) { s.handlers = append(s.handlers, h) } // SetAPIKeysHandler sets the API key management handler. -func (s *Server) SetAPIKeysHandler(h *httpapi.APIKeysHandler) { s.apiKeysHandler = h } +func (s *Server) SetAPIKeysHandler(h *httpapi.APIKeysHandler) { + s.handlers = append(s.handlers, h) +} // SetTenantsHandler sets the tenant management handler. -func (s *Server) SetTenantsHandler(h *httpapi.TenantsHandler) { s.tenantsHandler = h } +func (s *Server) SetTenantsHandler(h *httpapi.TenantsHandler) { + s.handlers = append(s.handlers, h) +} // SetAPIKeyStore sets the API key store for token-based auth lookup. func (s *Server) SetAPIKeyStore(st store.APIKeyStore) { s.apiKeyStore = st } // SetFilesHandler sets the workspace file serving handler. -func (s *Server) SetFilesHandler(h *httpapi.FilesHandler) { s.filesHandler = h } +func (s *Server) SetFilesHandler(h *httpapi.FilesHandler) { s.handlers = append(s.handlers, h) } // SetStorageHandler sets the storage file management handler. -func (s *Server) SetStorageHandler(h *httpapi.StorageHandler) { s.storageHandler = h } +func (s *Server) SetStorageHandler(h *httpapi.StorageHandler) { s.handlers = append(s.handlers, h) } // SetMediaUploadHandler sets the media upload handler. -func (s *Server) SetMediaUploadHandler(h *httpapi.MediaUploadHandler) { s.mediaUploadHandler = h } +func (s *Server) SetMediaUploadHandler(h *httpapi.MediaUploadHandler) { + s.handlers = append(s.handlers, h) +} // SetMediaServeHandler sets the media serve handler. -func (s *Server) SetMediaServeHandler(h *httpapi.MediaServeHandler) { s.mediaServeHandler = h } +func (s *Server) SetMediaServeHandler(h *httpapi.MediaServeHandler) { + s.handlers = append(s.handlers, h) +} // SetMemoryHandler sets the memory management handler. -func (s *Server) SetMemoryHandler(h *httpapi.MemoryHandler) { s.memoryHandler = h } +func (s *Server) SetMemoryHandler(h *httpapi.MemoryHandler) { s.handlers = append(s.handlers, h) } // SetKnowledgeGraphHandler sets the knowledge graph handler. -func (s *Server) SetKnowledgeGraphHandler(h *httpapi.KnowledgeGraphHandler) { s.kgHandler = h } +func (s *Server) SetKnowledgeGraphHandler(h *httpapi.KnowledgeGraphHandler) { + s.handlers = append(s.handlers, h) +} // SetActivityHandler sets the activity audit log handler. -func (s *Server) SetActivityHandler(h *httpapi.ActivityHandler) { s.activityHandler = h } +func (s *Server) SetActivityHandler(h *httpapi.ActivityHandler) { + s.handlers = append(s.handlers, h) +} // SetSystemConfigsHandler sets the system configs handler. -func (s *Server) SetSystemConfigsHandler(h *httpapi.SystemConfigsHandler) { s.systemConfigsHandler = h } +func (s *Server) SetSystemConfigsHandler(h *httpapi.SystemConfigsHandler) { + s.handlers = append(s.handlers, h) +} // SetUsageHandler sets the usage analytics handler. -func (s *Server) SetUsageHandler(h *httpapi.UsageHandler) { s.usageHandler = h } +func (s *Server) SetUsageHandler(h *httpapi.UsageHandler) { s.handlers = append(s.handlers, h) } // SetDocsHandler sets the OpenAPI spec + Swagger UI handler. -func (s *Server) SetDocsHandler(h *httpapi.DocsHandler) { s.docsHandler = h } +func (s *Server) SetDocsHandler(h *httpapi.DocsHandler) { s.handlers = append(s.handlers, h) } // SetAgentStore sets the agent store for context injection in tools_invoke. func (s *Server) SetAgentStore(as store.AgentStore) { s.agentStore = as }