diff --git a/internal/serviceadapter/router.go b/internal/serviceadapter/router.go index 224de67..01bf2cb 100644 --- a/internal/serviceadapter/router.go +++ b/internal/serviceadapter/router.go @@ -2,7 +2,11 @@ package serviceadapter import ( "fmt" + "net" "net/http" + "net/http/httputil" + "net/url" + "time" "forgejo.riotpiao.com/rock/homelab-frontend/internal/problem" ) @@ -104,12 +108,36 @@ func (d *Dispatcher) Dispatch(w http.ResponseWriter, r *http.Request) { } } - // TODO: Call upstream with method.UpstreamPath, apply retry logic, etc. - // For now, just echo that dispatch would happen - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{"service":"%s","resource":"%s","method":"%s","upstream":"%s"}`, - serviceName, resourceName, r.Method, adapter.Spec.Upstream.URL) + // Build upstream URL + upstreamURL, err := url.Parse(adapter.Spec.Upstream.URL) + if err != nil { + d.writeError(w, problem.NewProblem(http.StatusInternalServerError, "about:blank#server-error", + "Internal Server Error", fmt.Sprintf("invalid upstream URL: %v", err))) + return + } + + // Create reverse proxy with director that rewrites the path + proxy := httputil.NewSingleHostReverseProxy(upstreamURL) + proxy.Director = func(req *http.Request) { + req.URL.Scheme = upstreamURL.Scheme + req.URL.Host = upstreamURL.Host + req.URL.Path = method.UpstreamPath + req.RequestURI = "" + req.Host = upstreamURL.Host + } + + // Set timeout + timeout := adapter.Spec.Upstream.TimeoutSeconds + if timeout <= 0 { + timeout = 30 + } + proxy.Transport = &http.Transport{ + DialContext: (&net.Dialer{Timeout: time.Duration(timeout) * time.Second}).DialContext, + TLSHandshakeTimeout: time.Duration(timeout) * time.Second, + } + + // Forward the request + proxy.ServeHTTP(w, r) } // hasCapability checks if the request has the required capability.