package server import ( "net/http" "path/filepath" "strings" "github.com/gin-gonic/gin" ) type Options struct { UIServeDir string TemplateDir string StaticDir string EnableCORS bool } func NewRouter(opts Options) *gin.Engine { r := gin.New() r.Use(gin.Logger()) r.Use(gin.Recovery()) if opts.EnableCORS { r.Use(func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") if c.Request.Method == http.MethodOptions { c.AbortWithStatus(http.StatusNoContent) return } c.Next() }) } if strings.TrimSpace(opts.StaticDir) != "" { r.Static("/static", opts.StaticDir) } // Do not render legacy templates; keep core frontend under /ui api := r.Group("/api") { api.GET("/health", handleHealth) api.GET("/system/status", handleSystemStatus) api.GET("/stations", handleStations) api.GET("/data", handleData) api.GET("/forecast", handleForecast) api.GET("/radar/times", handleRadarTimes) api.GET("/radar/tiles_at", handleRadarTilesAt) api.GET("/rain/times", handleRainTimes) api.GET("/rain/tiles_at", handleRainTilesAt) } if strings.TrimSpace(opts.UIServeDir) != "" { // Serve built Angular assets under /ui for static files r.Static("/ui", opts.UIServeDir) // Serve Angular index.html at root r.GET("/", func(c *gin.Context) { c.File(filepath.Join(opts.UIServeDir, "index.html")) }) // Optional SPA fallback: serve index.html for non-API, non-static routes r.NoRoute(func(c *gin.Context) { p := c.Request.URL.Path if strings.HasPrefix(p, "/api/") || strings.HasPrefix(p, "/static/") { c.AbortWithStatus(http.StatusNotFound) return } c.File(filepath.Join(opts.UIServeDir, "index.html")) }) } return r }