ci / ts / ts (packages + web) (push) Canceled after 1m0s
ci / api / api (push) Successful in 46s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 56s
ci / db / db (push) Successful in 1m32s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m27s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m31s
Search hits omit album covers and artist images. The worker now reads the full song and artist, stores the description, and leaves Genius image URLs unchanged on mobile. Co-authored-by: Cursor <cursoragent@cursor.com>
103 lines
3.4 KiB
Go
103 lines
3.4 KiB
Go
// Package server собирает HTTP-роутер сервиса api из модулей.
|
|
package server
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
|
|
"pipu/api/internal/api/gen"
|
|
"pipu/api/internal/appupdate"
|
|
"pipu/api/internal/auth"
|
|
"pipu/api/internal/genius"
|
|
"pipu/api/internal/library"
|
|
"pipu/api/internal/platform/httpx"
|
|
"pipu/api/internal/playback"
|
|
"pipu/api/internal/search"
|
|
"pipu/api/internal/system"
|
|
"pipu/api/internal/uploads"
|
|
"pipu/api/internal/wave"
|
|
)
|
|
|
|
// Deps — модули, реализующие части контракта API.
|
|
type Deps struct {
|
|
Genius *genius.Handler
|
|
Log *slog.Logger
|
|
System *system.Handler
|
|
Auth *auth.Handler
|
|
// Library — хранилища, сканы и каталог.
|
|
Library *library.Handler
|
|
Search *search.Handler
|
|
// Playback — стрим, события, история, реакции, состояние плеера.
|
|
Playback *playback.Handler
|
|
// Wave — «Моя волна».
|
|
Wave *wave.Handler
|
|
App *appupdate.Handler
|
|
// Uploads — очередь на добавление; TUS — приём файлов (вне OpenAPI).
|
|
Uploads *uploads.Handler
|
|
TUS *uploads.TUS
|
|
// AuthService проверяет access-токены в middleware. nil — только для тестов служебных эндпоинтов.
|
|
AuthService *auth.Service
|
|
}
|
|
|
|
// handlers объединяет модули в единую реализацию gen.StrictServerInterface.
|
|
// По мере появления модулей (catalog, ...) они встраиваются сюда.
|
|
// Алиасы дают встроенным полям разные имена: у модулей одинаковое имя типа Handler.
|
|
type (
|
|
geniusHandler = genius.Handler
|
|
systemHandler = system.Handler
|
|
authHandler = auth.Handler
|
|
libraryHandler = library.Handler
|
|
searchHandler = search.Handler
|
|
playbackHandler = playback.Handler
|
|
waveHandler = wave.Handler
|
|
appHandler = appupdate.Handler
|
|
uploadsHandler = uploads.Handler
|
|
)
|
|
|
|
type handlers struct {
|
|
*geniusHandler
|
|
*systemHandler
|
|
*authHandler
|
|
*libraryHandler
|
|
*searchHandler
|
|
*playbackHandler
|
|
*waveHandler
|
|
*appHandler
|
|
*uploadsHandler
|
|
}
|
|
|
|
var _ gen.StrictServerInterface = handlers{}
|
|
|
|
// NewRouter возвращает корневой http.Handler.
|
|
func NewRouter(d Deps) http.Handler {
|
|
log := d.Log
|
|
if log == nil {
|
|
log = slog.New(slog.DiscardHandler)
|
|
}
|
|
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.RequestID, httpx.RealIP, httpx.AccessLog(log), middleware.Recoverer)
|
|
if d.AuthService != nil {
|
|
r.Use(auth.Middleware(d.AuthService, log))
|
|
}
|
|
r.NotFound(httpx.NotFound)
|
|
r.MethodNotAllowed(httpx.MethodNotAllowed)
|
|
if d.TUS != nil {
|
|
d.TUS.Mount(r)
|
|
}
|
|
|
|
strict := gen.NewStrictHandlerWithOptions(handlers{geniusHandler: d.Genius, systemHandler: d.System, authHandler: d.Auth, libraryHandler: d.Library, searchHandler: d.Search, playbackHandler: d.Playback, waveHandler: d.Wave, appHandler: d.App, uploadsHandler: d.Uploads},
|
|
[]gen.StrictMiddlewareFunc{httpx.StrictRequest}, gen.StrictHTTPServerOptions{
|
|
RequestErrorHandlerFunc: httpx.RequestError,
|
|
ResponseErrorHandlerFunc: httpx.ResponseError(log),
|
|
})
|
|
return gen.HandlerWithOptions(strict, gen.ChiServerOptions{
|
|
BaseRouter: r,
|
|
// Ошибки разбора path- и query-параметров — тоже problem+json, а не текст по умолчанию.
|
|
ErrorHandlerFunc: httpx.RequestError,
|
|
})
|
|
}
|