mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-01 16:48:19 +00:00
121 lines
4.8 KiB
Go
121 lines
4.8 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
// Package router wires all HTTP routes onto the Chi router and injects
|
|
// dependencies (hub, reader, ingest workers) into the handler closures.
|
|
// All routes are mounted under /api/v1 with public and private groups
|
|
// stubbed for future auth middleware.
|
|
package router
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/go-chi/cors"
|
|
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/api"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/api/handlers"
|
|
mw "github.com/MeshCore-Beacon/beacon-server/internal/api/middleware"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/config"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/hub"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/ingest"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/ws"
|
|
httpSwagger "github.com/swaggo/http-swagger"
|
|
)
|
|
|
|
// New builds and returns the top-level Chi router.
|
|
//
|
|
// Route shape:
|
|
//
|
|
// /ws → WebSocket (public in v1)
|
|
// /api/v1/ → public group
|
|
// /packets → packets subrouter
|
|
// /nodes → nodes subrouter
|
|
// /brokers → brokers subrouter
|
|
// /observers → observers subrouter
|
|
// /channels → channels subrouter
|
|
// /iatas → iatas subrouter
|
|
// /regions → regions subrouter
|
|
// /stats → stats subrouter
|
|
//
|
|
// The private group is stubbed and ready for the auth middleware drop-in
|
|
// described in Future Features → Admin authentication.
|
|
func New(h *hub.Hub, reader api.Reader, workers []*ingest.Worker, maxConnsPerIP int, corsCfg config.CORSConfig) http.Handler {
|
|
r := chi.NewRouter()
|
|
|
|
// ── CORS ─────────────────────────────────────────────────────────────────
|
|
allowedOrigins := corsCfg.AllowedOrigins
|
|
if len(allowedOrigins) == 0 {
|
|
allowedOrigins = []string{"*"}
|
|
}
|
|
allowedMethods := corsCfg.AllowedMethods
|
|
if len(allowedMethods) == 0 {
|
|
allowedMethods = []string{"GET", "HEAD", "OPTIONS"}
|
|
}
|
|
allowedHeaders := corsCfg.AllowedHeaders
|
|
if len(allowedHeaders) == 0 {
|
|
allowedHeaders = []string{"Accept", "Authorization", "Content-Type"}
|
|
}
|
|
maxAge := corsCfg.MaxAge
|
|
if maxAge == 0 {
|
|
maxAge = 300
|
|
}
|
|
r.Use(cors.Handler(cors.Options{
|
|
AllowedOrigins: allowedOrigins,
|
|
AllowedMethods: allowedMethods,
|
|
AllowedHeaders: allowedHeaders,
|
|
AllowCredentials: corsCfg.AllowCredentials,
|
|
MaxAge: maxAge,
|
|
}))
|
|
|
|
// ── Global middleware ────────────────────────────────────────────────────
|
|
r.Use(middleware.RequestID)
|
|
r.Use(middleware.RealIP)
|
|
r.Use(middleware.Logger)
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(middleware.CleanPath)
|
|
r.Use(middleware.StripSlashes)
|
|
|
|
// ── Swagger UI ──────────────────────────────────────────────────────────
|
|
r.Get("/swagger", func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/swagger/index.html", http.StatusMovedPermanently)
|
|
})
|
|
|
|
r.Get("/swagger/*", httpSwagger.Handler(
|
|
httpSwagger.URL("/swagger/doc.json"),
|
|
))
|
|
|
|
// ── WebSocket ────────────────────────────────────────────────────────────
|
|
r.Get("/ws", ws.Handler(h, reader, maxConnsPerIP))
|
|
|
|
// ── Public REST API (v1) ─────────────────────────────────────────────────
|
|
r.Route("/api/v1", func(r chi.Router) {
|
|
// Public group — no authentication required (all of v1 is public).
|
|
r.Group(func(r chi.Router) {
|
|
r.Mount("/packets", handlers.PacketsRouter(reader))
|
|
r.Mount("/nodes", handlers.NodesRouter(reader))
|
|
r.Mount("/brokers", handlers.BrokersRouter(workers))
|
|
r.Mount("/observers", handlers.ObserversRouter(reader))
|
|
r.Mount("/channels", handlers.ChannelsRouter(reader))
|
|
r.Mount("/messages", handlers.MessagesRouter(reader))
|
|
r.Mount("/iatas", handlers.IATAsRouter(reader))
|
|
r.Mount("/regions", handlers.RegionsRouter(reader))
|
|
r.Mount("/routes", handlers.RoutesRouter(reader))
|
|
r.Mount("/scopes", handlers.ScopesRouter(reader))
|
|
r.Mount("/stats", handlers.StatsRouter(reader))
|
|
r.Mount("/traces", handlers.TracesRouter(reader))
|
|
})
|
|
|
|
// Private group — auth middleware applied.
|
|
// Stubbed for the admin endpoints described in Future Features.
|
|
// Swap mw.NoopAuth for a real JWT/session middleware when ready.
|
|
r.Group(func(r chi.Router) {
|
|
r.Use(mw.NoopAuth)
|
|
// r.Mount("/admin", handlers.AdminRouter())
|
|
})
|
|
})
|
|
|
|
return r
|
|
}
|