0.1.38 gateway
This commit is contained in:
@@ -22,17 +22,20 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ponzischeme89/memby/server/internal/adminevents"
|
||||
"github.com/ponzischeme89/memby/server/internal/appupdate"
|
||||
"github.com/ponzischeme89/memby/server/internal/bazarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/cache"
|
||||
"github.com/ponzischeme89/memby/server/internal/config"
|
||||
"github.com/ponzischeme89/memby/server/internal/emby"
|
||||
"github.com/ponzischeme89/memby/server/internal/foryou"
|
||||
"github.com/ponzischeme89/memby/server/internal/integrations"
|
||||
serverlogging "github.com/ponzischeme89/memby/server/internal/logging"
|
||||
"github.com/ponzischeme89/memby/server/internal/mdblist"
|
||||
"github.com/ponzischeme89/memby/server/internal/opensubtitles"
|
||||
"github.com/ponzischeme89/memby/server/internal/radarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/recommend"
|
||||
"github.com/ponzischeme89/memby/server/internal/scheduler"
|
||||
"github.com/ponzischeme89/memby/server/internal/sonarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/store"
|
||||
)
|
||||
@@ -51,7 +54,14 @@ type Server struct {
|
||||
syncer syncerHandle
|
||||
log *slog.Logger
|
||||
events *serverlogging.Buffer
|
||||
sonarrMu sync.Mutex
|
||||
// adminEvents is the administrative feed: the console's notification bell and every
|
||||
// outgoing integration read from it. Distinct from `events` above, which is the
|
||||
// structured log ring — a log line is what the gateway did, an admin event is
|
||||
// something an operator would want to be told.
|
||||
adminEvents *adminevents.Bus
|
||||
scheduler *scheduler.Scheduler
|
||||
integrations *integrations.Dispatcher
|
||||
sonarrMu sync.Mutex
|
||||
// sonarrSeriesMu guards the catalogue cache separately from the calendar's, so an add
|
||||
// to My Shows never waits behind a launcher rebuilding the schedule row.
|
||||
sonarrSeriesMu sync.Mutex
|
||||
@@ -85,6 +95,9 @@ type Server struct {
|
||||
// embyHealth is the reachability probe's live finding, which /v1/status publishes so
|
||||
// a TV can show why playback stopped even if it missed the announcement.
|
||||
embyHealth embyHealth
|
||||
|
||||
// The console is a separate container the gateway proxies; see admin_spa.go.
|
||||
adminUIHandle
|
||||
}
|
||||
|
||||
// Deps are the collaborators the API needs. A struct rather than positional arguments:
|
||||
@@ -102,6 +115,10 @@ type Deps struct {
|
||||
Syncer syncerHandle
|
||||
Log *slog.Logger
|
||||
Events *serverlogging.Buffer
|
||||
|
||||
AdminEvents *adminevents.Bus
|
||||
Scheduler *scheduler.Scheduler
|
||||
Integrations *integrations.Dispatcher
|
||||
}
|
||||
|
||||
func New(cfg config.Config, deps Deps) *Server {
|
||||
@@ -119,9 +136,23 @@ func New(cfg config.Config, deps Deps) *Server {
|
||||
syncer: deps.Syncer,
|
||||
log: deps.Log,
|
||||
events: deps.Events,
|
||||
|
||||
adminEvents: deps.AdminEvents,
|
||||
scheduler: deps.Scheduler,
|
||||
integrations: deps.Integrations,
|
||||
}
|
||||
}
|
||||
|
||||
// publishAdmin reports something an operator would want to know about.
|
||||
//
|
||||
// Every caller treats it as fire-and-forget, which is why it returns nothing: the feed is
|
||||
// a convenience over things that are already logged, and a bell that could fail a sign-in
|
||||
// would be worse than no bell. A server built without a bus — every unit test in this
|
||||
// package — publishes into a nil receiver, which is a no-op.
|
||||
func (s *Server) publishAdmin(ctx context.Context, event adminevents.Event) {
|
||||
s.adminEvents.Publish(ctx, event)
|
||||
}
|
||||
|
||||
func (s *Server) Routes() http.Handler {
|
||||
// The client API lives on its own mux so maintenance mode can gate all of it at
|
||||
// once, without the gate ever touching health checks or the admin page.
|
||||
@@ -225,6 +256,12 @@ func (s *Server) Routes() http.Handler {
|
||||
// Radarr pushes here when an import finishes. Outside the gate on purpose: an event
|
||||
// arriving during maintenance would otherwise be lost rather than delayed.
|
||||
mux.HandleFunc("POST /hooks/radarr", s.handleRadarrWebhook)
|
||||
// State the canonical console URL explicitly. The console and its assets live below
|
||||
// /admin/, while a bare /admin is routinely typed and some reverse proxies do not
|
||||
// preserve ServeMux's implicit trailing-slash redirect for a mounted subtree.
|
||||
mux.HandleFunc("GET /admin", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/admin/", http.StatusFound)
|
||||
})
|
||||
mux.Handle("/admin/", s.adminRoutes())
|
||||
mux.HandleFunc("GET /{$}", s.handleInstallPage)
|
||||
mux.HandleFunc("GET /install", s.handleInstallPage)
|
||||
@@ -441,6 +478,16 @@ func (r *statusRecorder) WriteHeader(code int) {
|
||||
r.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// Flush preserves streaming support through the request logger. In particular, the admin
|
||||
// notification feed is Server-Sent Events and correctly refuses to start unless its writer
|
||||
// implements http.Flusher. Embedding ResponseWriter alone does not promote optional
|
||||
// interfaces, so the old recorder turned every stream request into a 500.
|
||||
func (r *statusRecorder) Flush() {
|
||||
if flusher, ok := r.ResponseWriter.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
// --- sessions ---------------------------------------------------------------
|
||||
|
||||
func bearerToken(r *http.Request) string {
|
||||
|
||||
Reference in New Issue
Block a user