diff --git a/app/web/main.go b/app/web/main.go index 7d9bbee..735d38a 100644 --- a/app/web/main.go +++ b/app/web/main.go @@ -48,6 +48,54 @@ func parseLogLevel(s string) int { } } +// proxyToValhallaPOST forwards a POST with JSON body to a specific Valhalla endpoint (e.g., /isochrone) +func proxyToValhallaPOST(w http.ResponseWriter, r *http.Request, target string) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + req, err := http.NewRequestWithContext(r.Context(), http.MethodPost, target, r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + req.Header = r.Header.Clone() + if req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "application/json") + } + + client := http.Client{Timeout: 20 * time.Second} + start := time.Now() + resp, err := client.Do(req) + if err != nil { + if rid, ok := r.Context().Value(ctxReqID).(string); ok { + logf(levelError, "rid=%s upstream=valhalla target=%s error=%v", rid, target, err) + } else { + logf(levelError, "upstream=valhalla target=%s error=%v", target, err) + } + http.Error(w, err.Error(), http.StatusBadGateway) + return + } + defer resp.Body.Close() + + // Forward common headers and status + for key, values := range resp.Header { + if key == "Content-Type" || key == "Content-Encoding" || key == "Cache-Control" || key == "Vary" { + for _, v := range values { + w.Header().Add(key, v) + } + } + } + w.WriteHeader(resp.StatusCode) + _, _ = io.Copy(w, resp.Body) + + if rid, ok := r.Context().Value(ctxReqID).(string); ok { + logf(levelDebug, "rid=%s upstream=valhalla target=%s status=%d dur=%s", rid, target, resp.StatusCode, time.Since(start)) + } else { + logf(levelDebug, "upstream=valhalla target=%s status=%d dur=%s", target, resp.StatusCode, time.Since(start)) + } +} + func logf(level int, format string, args ...any) { if level < currentLogLevel { return @@ -74,6 +122,8 @@ func main() { if valhallaURL == "" { valhallaURL = "http://valhalla:8002/route" } + // Derive Valhalla base for other endpoints like /isochrone + valhallaBase := strings.TrimSuffix(valhallaURL, "/route") nominatimBase := os.Getenv("NOMINATIM_URL") if nominatimBase == "" { @@ -100,6 +150,15 @@ func main() { http.Handle("/route", withLogging(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { proxyToValhalla(w, r, valhallaURL) }))) + http.Handle("/isochrone", withLogging(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Forward to Valhalla isochrone endpoint (POST JSON) + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + target := valhallaBase + "/isochrone" + proxyToValhallaPOST(w, r, target) + }))) // Nominatim proxy endpoints http.Handle("/geocode", withLogging(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { proxyToNominatimGET(w, r, nominatimBase+"/search", nominatimUA) diff --git a/app/web/static/index.html b/app/web/static/index.html index fa8c051..9e91986 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -9,7 +9,7 @@ - +