diff options
Diffstat (limited to 'backend/internal/api')
| -rw-r--r-- | backend/internal/api/router.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/backend/internal/api/router.go b/backend/internal/api/router.go index d28da71..a88ffbd 100644 --- a/backend/internal/api/router.go +++ b/backend/internal/api/router.go @@ -1,8 +1,12 @@ package api import ( + "io/fs" + "log" "net/http" "strings" + + "yaum/internal/static" ) func NewRouter(h *Handler, stream *StreamHandler, auth *AuthHandler) http.Handler { @@ -33,9 +37,88 @@ func NewRouter(h *Handler, stream *StreamHandler, auth *AuthHandler) http.Handle mux.Handle("GET /api/stream", stream) + // Static file serving — register only if build FS is available + if buildFS := static.BuildFS(); buildFS != nil { + staticHandler := spaFileServer(buildFS) + mux.HandleFunc("/", staticHandler.ServeHTTP) + } else { + log.Println("[router] nenhum build frontend encontrado — servindo apenas API") + // Still register root to give a friendly message + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/api") { + http.NotFound(w, r) + return + } + w.WriteHeader(http.StatusOK) + w.Write([]byte(`YAUM API — frontend build not available. +Start the frontend dev server (npm run dev) or set YAUM_STATIC_DIR.`)) + }) + } + return corsMiddleware(auth.Middleware(mux)) } +// spaFileServer returns an http.Handler that serves static files and falls +// back to index.html (or 200.html) for SPA routes like /admin, /status/123. +// Only GET/HEAD requests are handled; other methods return 405. +func spaFileServer(fsys fs.FS) http.Handler { + fileServer := http.FileServer(http.FS(fsys)) + + exists := func(name string) bool { + f, err := fsys.Open(name) + if err != nil { + return false + } + f.Close() + return true + } + + // Determine which SPA fallback file exists + fallbackFile := "200.html" + fallbackBytes, fallbackErr := fs.ReadFile(fsys, fallbackFile) + if fallbackErr != nil { + fallbackFile = "index.html" + fallbackBytes, fallbackErr = fs.ReadFile(fsys, fallbackFile) + } + if fallbackErr != nil { + log.Printf("[router] nenhum fallback SPA (200.html/index.html) encontrado") + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Only serve GET/HEAD for static files + if r.Method != http.MethodGet && r.Method != http.MethodHead { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // API paths should already be handled by the mux, but just in case + if strings.HasPrefix(r.URL.Path, "/api") { + http.NotFound(w, r) + return + } + + p := strings.TrimPrefix(r.URL.Path, "/") + + // Root path or non-existent file → serve SPA fallback + if p == "" || !exists(p) { + if fallbackErr == nil { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusOK) + w.Write(fallbackBytes) + return + } + http.NotFound(w, r) + return + } + + fileServer.ServeHTTP(w, r) + }) +} + + + + + func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") |