package api import ( "net/http" "os" "path/filepath" "strings" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "crypto-miner-server/internal/db" "crypto-miner-server/internal/builder" ) func NewRouter(database *db.Database, wsHub *WSHub, configHandler *ConfigHandler, builderHandler *builder.Handler, webRoot string) http.Handler { r := chi.NewRouter() // Middleware r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"}, AllowCredentials: true, })) // REST API r.Route("/api/v1", func(r chi.Router) { h := NewHandler(database) r.Get("/health", h.HealthCheck) // Dashboard r.Get("/dashboard/stats", h.GetDashboardStats) // Agents r.Get("/agents", h.ListAgents) r.Get("/agents/{id}", h.GetAgent) r.Get("/agents/{id}/stats", h.GetAgentStats) // Shares r.Get("/shares", h.GetRecentShares) // Builds r.Get("/builds", h.ListBuilds) r.Get("/builds/{id}/download", builderHandler.DownloadBuild) // Config r.Get("/config", configHandler.ServeHTTP) r.Put("/config", configHandler.ServeHTTP) // Builder r.Post("/builder/build", builderHandler.ServeHTTP) }) // WebSocket r.Get("/ws/agent", wsHub.HandleAgentWS) r.Get("/ws/dashboard", wsHub.HandleDashboardWS) // Serve frontend SPA if webRoot != "" { // Check if webroot directory exists if info, err := os.Stat(webRoot); err == nil && info.IsDir() { // Create a file server for the webroot fileServer := http.FileServer(http.Dir(webRoot)) // SPA fallback: serve index.html for all non-API, non-WebSocket routes r.Get("/*", func(w http.ResponseWriter, r *http.Request) { // Clean the path path := strings.TrimPrefix(r.URL.Path, "/") fullPath := filepath.Join(webRoot, path) // Check if the file exists if _, err := os.Stat(fullPath); err == nil { fileServer.ServeHTTP(w, r) return } // SPA fallback - serve index.html http.ServeFile(w, r, filepath.Join(webRoot, "index.html")) }) } else { // Fallback if webroot doesn't exist r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.Write([]byte(`
Server is running. Build the frontend with cd server/web && npm install && npm run build
API: /api/v1/health
`)) }) } } else { r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.Write([]byte(`Server is running. No frontend configured.
API: /api/v1/health
`)) }) } return r }