aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/internal/api/router.go83
-rw-r--r--backend/internal/static/static.go43
2 files changed, 126 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")
diff --git a/backend/internal/static/static.go b/backend/internal/static/static.go
new file mode 100644
index 0000000..53523a3
--- /dev/null
+++ b/backend/internal/static/static.go
@@ -0,0 +1,43 @@
+package static
+
+import (
+ "embed"
+ "io/fs"
+ "log"
+ "os"
+ "path/filepath"
+)
+
+//go:embed build
+var embeddedBuild embed.FS
+
+func BuildFS() fs.FS {
+ sub, err := fs.Sub(embeddedBuild, "build")
+ if err != nil {
+ log.Printf("[static] embed nao disponivel, tentando filesystem: %v", err)
+ // Fallback: look for build directory relative to the backend binary
+ dir := os.Getenv("YAUM_STATIC_DIR")
+ if dir == "" {
+ // Try common locations
+ candidates := []string{
+ "../frontend/build",
+ "frontend/build",
+ "./build",
+ }
+ for _, c := range candidates {
+ if info, e := os.Stat(c); e == nil && info.IsDir() {
+ dir = c
+ break
+ }
+ }
+ }
+ if dir != "" {
+ abs, _ := filepath.Abs(dir)
+ log.Printf("[static] servindo de %s", abs)
+ return os.DirFS(dir)
+ }
+ return nil
+ }
+ log.Println("[static] servindo de embed")
+ return sub
+}