Files
mal/internal/server/routes.go

92 lines
3.7 KiB
Go

package server
import (
"database/sql"
"net/http"
"mal/api/anime"
"mal/api/auth"
"mal/api/playback"
"mal/api/watchlist"
"mal/integrations/jikan"
"mal/internal/db"
"mal/internal/middleware"
pkgmiddleware "mal/pkg/middleware"
)
type Config struct {
DB *database.Queries
SQLDB *sql.DB
JikanClient *jikan.Client
AuthService *auth.Service
PlaybackProxySecret string
}
func NewRouter(cfg Config) http.Handler {
mux := http.NewServeMux()
authHandler := auth.NewHandler(cfg.AuthService)
watchlistSvc := watchlist.NewService(cfg.DB, cfg.SQLDB)
watchlistHandler := watchlist.NewHandler(watchlistSvc)
animeHandler := anime.NewHandler(cfg.JikanClient, cfg.DB)
playbackSvc := playback.NewService(cfg.DB, cfg.SQLDB, playback.Config{ProxyTokenSecret: cfg.PlaybackProxySecret})
playbackHandler := playback.NewHandler(playbackSvc, cfg.JikanClient)
// Serve static files
fs := http.FileServer(http.Dir("./static"))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
// Serve built frontend assets
dist := http.FileServer(http.Dir("./dist"))
mux.Handle("/dist/", http.StripPrefix("/dist/", dist))
mux.HandleFunc("/", animeHandler.HandleCatalog)
mux.HandleFunc("/discover", animeHandler.HandleDiscover)
mux.HandleFunc("/continue-watching", watchlistHandler.HandleContinueWatching)
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/continue-watching", http.StatusMovedPermanently)
})
mux.HandleFunc("/api/discover/airing", animeHandler.HandleAPIDiscoverAiring)
mux.HandleFunc("/api/discover/upcoming", animeHandler.HandleAPIDiscoverUpcoming)
mux.HandleFunc("/search", animeHandler.HandleSearch)
mux.HandleFunc("/api/search", animeHandler.HandleAPISearch)
mux.HandleFunc("/api/search-quick", animeHandler.HandleQuickSearch)
mux.HandleFunc("/api/catalog", animeHandler.HandleAPICatalog)
mux.HandleFunc("/anime/", animeHandler.HandleAnimeDetails)
mux.HandleFunc("/api/anime/", animeHandler.HandleAPIAnime)
mux.HandleFunc("/api/episodes/", animeHandler.HandleAPIEpisodes)
mux.HandleFunc("/studios/", animeHandler.HandleStudioDetails)
mux.HandleFunc("/api/studios/", animeHandler.HandleAPIStudioAnime)
mux.HandleFunc("/watch/", playbackHandler.HandleWatchPage)
mux.HandleFunc("/watch/proxy/stream", playbackHandler.HandleProxy)
mux.HandleFunc("/watch/proxy/segment", playbackHandler.HandleProxy)
mux.HandleFunc("/watch/proxy/subtitle", playbackHandler.HandleProxy)
mux.HandleFunc("/api/watch-progress", playbackHandler.HandleSaveProgress)
mux.HandleFunc("/api/watch-complete", playbackHandler.HandleCompleteAnime)
// Auth Endpoints
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
authHandler.HandleLoginPage(w, r)
} else {
pkgmiddleware.RateLimitAuth(pkgmiddleware.VerifyOrigin(http.HandlerFunc(authHandler.HandleLogin))).ServeHTTP(w, r)
}
})
// Watchlist Endpoints
mux.HandleFunc("/api/watchlist/export", watchlistHandler.HandleExportWatchlist)
mux.HandleFunc("/api/watchlist/import", watchlistHandler.HandleImportWatchlist)
mux.HandleFunc("/api/watchlist", watchlistHandler.HandleUpdateWatchlist)
mux.HandleFunc("/api/watchlist/", watchlistHandler.HandleDeleteWatchlist)
mux.HandleFunc("/api/continue-watching/", watchlistHandler.HandleDeleteContinueWatching)
mux.HandleFunc("/watchlist", watchlistHandler.HandleGetWatchlist)
// Wrap mux with global CSRF origin verification and auth checking,
// THEN auth context parsing.
protectedHandler := middleware.RequireGlobalAuthWithPolicy(middleware.NewAccessPolicy())(pkgmiddleware.VerifyOrigin(mux))
authenticatedHandler := middleware.Auth(cfg.AuthService)(protectedHandler)
return pkgmiddleware.RequestLogger(authenticatedHandler)
}