package server import ( "net/http" "strings" "forgejo.riotpiao.com/rock/homelab-frontend/internal/serviceadapter" ) // Router implements an HTTP handler that routes health endpoints, // ServiceAdapter X-Service requests, Temporal workflow endpoints, // S3/SigV4 endpoints, and other requests to upstream handlers. type Router struct { healthChecker *HealthChecker dispatcher *serviceadapter.Dispatcher temporalHandler http.Handler s3Handler http.Handler // S3/SigV4 proxy upstreamHandler http.Handler } // NewRouter creates a new router with health endpoints. // Health endpoints (/healthz and /readyz) are handled locally. // X-Service requests are dispatched via ServiceAdapter CRD. // Temporal endpoints (/workflow*) are routed to temporalHandler. // S3 endpoints (/v1/s3/*) are routed to s3Handler. // All other paths are passed to the upstream handler. func NewRouter(healthChecker *HealthChecker, dispatcher *serviceadapter.Dispatcher, temporalHandler http.Handler, s3Handler http.Handler, upstreamHandler http.Handler) *Router { return &Router{ healthChecker: healthChecker, dispatcher: dispatcher, temporalHandler: temporalHandler, s3Handler: s3Handler, upstreamHandler: upstreamHandler, } } // ServeHTTP implements http.Handler. // Priority order: // 1. /healthz and /readyz to health handlers // 2. X-Service header to ServiceAdapter dispatcher (phase 8) // 3. /workflow* to temporal handler // 4. /v1/s3/* to S3/SigV4 handler // 5. All other paths to upstream handler (phase 0-7) func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Health endpoints first switch req.URL.Path { case "/healthz": LivenessHandler(r.healthChecker)(w, req) return case "/readyz": ReadinessHandler(r.healthChecker)(w, req) return } // X-Service (ServiceAdapter) routing - checked before path-based routing if req.Header.Get("X-Service") != "" { if r.dispatcher != nil { r.dispatcher.Dispatch(w, req) return } } // Workflow endpoints switch req.URL.Path { case "/workflow", "/workflow/health", "/workflow/metrics": r.temporalHandler.ServeHTTP(w, req) return } // S3/SigV4 proxy endpoints if req.URL.Path != "" && req.URL.Path[0] == '/' && len(req.URL.Path) > 1 { // Check for /v1/s3/* pattern parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/") if len(parts) >= 3 && parts[0] == "v1" && parts[1] == "s3" { if r.s3Handler != nil { r.s3Handler.ServeHTTP(w, req) return } } } // Default: upstream handler (all other paths) r.upstreamHandler.ServeHTTP(w, req) }