0.1.38 gateway
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/ponzischeme89/memby/server/internal/adminevents"
|
||||
"github.com/ponzischeme89/memby/server/internal/api"
|
||||
"github.com/ponzischeme89/memby/server/internal/bazarr"
|
||||
"github.com/ponzischeme89/memby/server/internal/buildinfo"
|
||||
@@ -23,11 +24,13 @@ import (
|
||||
"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"
|
||||
"github.com/ponzischeme89/memby/server/internal/library"
|
||||
"github.com/ponzischeme89/memby/server/internal/logging"
|
||||
"github.com/ponzischeme89/memby/server/internal/mdblist"
|
||||
"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"
|
||||
"github.com/ponzischeme89/memby/server/internal/tracearr"
|
||||
@@ -172,6 +175,16 @@ func run(log *slog.Logger, events *logging.Buffer) error {
|
||||
})
|
||||
}
|
||||
|
||||
// The administrative event bus, the integration dispatcher that subscribes to it and
|
||||
// the scheduler that publishes into it are built before the server, because the server
|
||||
// takes all three: a handler that could not publish would have to check for nil at
|
||||
// every call site, which is exactly how an event comes to be silently dropped.
|
||||
adminBus := adminevents.New(st, log)
|
||||
dispatcher := integrations.New(st, log, adminBus)
|
||||
adminBus.AddSink(dispatcher)
|
||||
dispatcher.Start(ctx)
|
||||
sched := scheduler.New(st, log, adminBus)
|
||||
|
||||
server := api.New(cfg, api.Deps{
|
||||
Emby: embyClient,
|
||||
Store: st,
|
||||
@@ -185,8 +198,17 @@ func run(log *slog.Logger, events *logging.Buffer) error {
|
||||
Syncer: syncer,
|
||||
Log: log,
|
||||
Events: events,
|
||||
|
||||
AdminEvents: adminBus,
|
||||
Scheduler: sched,
|
||||
Integrations: dispatcher,
|
||||
})
|
||||
|
||||
// Registration is separate from construction so the task list reads as a declaration
|
||||
// of what the gateway does in the background rather than as more wiring in here.
|
||||
server.RegisterHousekeeping(sched)
|
||||
sched.Start(ctx)
|
||||
|
||||
// Installed after the server exists, because both halves of a finished import are
|
||||
// its business: derived data has to be invalidated, and the TVs told the catalogue
|
||||
// moved. Kept off the syncer itself so library stays ignorant of the API.
|
||||
@@ -251,8 +273,6 @@ func run(log *slog.Logger, events *logging.Buffer) error {
|
||||
}
|
||||
}()
|
||||
}
|
||||
go pruneAnalytics(ctx, st, cfg.AnalyticsRetention, log)
|
||||
|
||||
httpServer := &http.Server{
|
||||
Addr: cfg.ListenAddr,
|
||||
Handler: server.Routes(),
|
||||
@@ -261,8 +281,6 @@ func run(log *slog.Logger, events *logging.Buffer) error {
|
||||
IdleTimeout: 60 * time.Second,
|
||||
}
|
||||
|
||||
go sweepIdleSessions(ctx, st, cfg.SessionIdleExpiry, log)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
log.Info("gateway ready",
|
||||
@@ -271,6 +289,9 @@ func run(log *slog.Logger, events *logging.Buffer) error {
|
||||
"protocol", api.ProtocolVersion,
|
||||
"sync_every", cfg.SyncInterval,
|
||||
)
|
||||
// Announced here rather than beside the log line above, so the feed cannot record
|
||||
// a start that then failed to bind to its port.
|
||||
server.AnnounceServerStart(buildinfo.Version())
|
||||
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
errCh <- err
|
||||
}
|
||||
@@ -328,48 +349,4 @@ func openStore(ctx context.Context, databaseURL string, log *slog.Logger) (*stor
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
// pruneAnalytics keeps raw engagement and journey events inside their retention window.
|
||||
func pruneAnalytics(ctx context.Context, st *store.Store, retention time.Duration, log *slog.Logger) {
|
||||
if retention <= 0 {
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
removed, err := st.PruneRowEvents(ctx, retention)
|
||||
if err != nil {
|
||||
log.Warn("analytics prune failed", "error", err)
|
||||
continue
|
||||
}
|
||||
if removed > 0 {
|
||||
log.Info("pruned row events", "count", removed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sweepIdleSessions retires gateway tokens that have not been used in a long time, so a
|
||||
// TV that was factory-reset does not leave a live Emby token in the database forever.
|
||||
func sweepIdleSessions(ctx context.Context, st *store.Store, idle time.Duration, log *slog.Logger) {
|
||||
ticker := time.NewTicker(6 * time.Hour)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
removed, err := st.DeleteIdleSessions(ctx, idle)
|
||||
if err != nil {
|
||||
log.Warn("session sweep failed", "error", err)
|
||||
continue
|
||||
}
|
||||
if removed > 0 {
|
||||
log.Info("retired idle sessions", "count", removed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user