// Package api provides the main API router and route handlers for the Triggersmith application. package api import ( "encoding/json" "log/slog" "net/http" "path/filepath" "time" api_auth "git.oblat.lv/alex/triggerssmith/api/auth" api_block "git.oblat.lv/alex/triggerssmith/api/block" "git.oblat.lv/alex/triggerssmith/internal/auth" "git.oblat.lv/alex/triggerssmith/internal/config" "git.oblat.lv/alex/triggerssmith/internal/vars" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) type Router struct { r chi.Router cfg *config.Config authService *auth.AuthService } type RouterDependencies struct { AuthService *auth.AuthService Configuration *config.Config } func NewRouter(deps RouterDependencies) *Router { if deps.AuthService == nil { panic("AuthService is required") } if deps.Configuration == nil { panic("Configuration is required") } r := chi.NewRouter() return &Router{ r: r, cfg: deps.Configuration, authService: deps.AuthService, } } // RouteHandler sets up the routes and middleware for the router. // TODO: implement hot reload for static files enabled/disabled func (r *Router) MustRoute() chi.Router { r.r.Use(middleware.Logger) r.r.Use(middleware.Recoverer) r.r.Use(middleware.Timeout(r.cfg.Server.TimeoutSeconds)) if r.cfg.Server.StaticConfig.Enabled { slog.Debug("Static file serving is enabled", slog.String("dir", r.cfg.Server.StaticConfig.Dir), slog.String("index_file", r.cfg.Server.StaticConfig.IndexFile), ) r.r.Get("/", func(w http.ResponseWriter, req *http.Request) { http.ServeFile(w, req, filepath.Join(r.cfg.Server.StaticConfig.Dir, r.cfg.Server.StaticConfig.IndexFile)) }) fs := http.FileServer(http.Dir(r.cfg.Server.StaticConfig.Dir)) r.r.Handle("/static/*", http.StripPrefix("/static/", fs)) } else { slog.Info("Static file serving is disabled") r.r.Get("/", func(w http.ResponseWriter, req *http.Request) { http.Error(w, "Static serving is disabled", http.StatusForbidden) }) r.r.HandleFunc("/static/*", func(w http.ResponseWriter, req *http.Request) { http.Error(w, "Static serving is disabled", http.StatusForbidden) }) } r.r.Route("/api", func(api chi.Router) { api.Route("/block", api_block.MustRoute(r.cfg)) api.Route("/auth", api_auth.MustRoute(r.cfg)) }) r.r.Get("/health", func(w http.ResponseWriter, r *http.Request) { b, _ := json.Marshal(struct { Status string `json:"status"` Uptime string `json:"uptime"` }{ Status: "ok", Uptime: time.Since(vars.START_TIME).String(), }) w.Write([]byte(b)) }) //r.r.Handle("/invoke/function/{function_id}/{function_version}", invoke.InvokeHandler(r.cfg)) return r.r }