package main import ( "context" "encoding/json" "net/http" "sync" "time" ) const totalsInterval = 300 * time.Second // _refresh_total_rares_cache cadence // totalsCache holds the pre-marshaled bodies for /total-rares and /total-kills, // refreshed every totalsInterval, mirroring main.py:924. type totalsCache struct { mu sync.RWMutex raresJSON []byte killsJSON []byte } func newTotalsCache() *totalsCache { return &totalsCache{ raresJSON: []byte(`{"all_time":0,"today":0,"last_updated":null}`), killsJSON: []byte(`{"total":0,"last_updated":null}`), } } func (c *totalsCache) getRares() []byte { c.mu.RLock(); defer c.mu.RUnlock(); return c.raresJSON } func (c *totalsCache) getKills() []byte { c.mu.RLock(); defer c.mu.RUnlock(); return c.killsJSON } func (c *totalsCache) set(rares, kills []byte) { c.mu.Lock() defer c.mu.Unlock() c.raresJSON = rares c.killsJSON = kills } func (s *Server) refreshTotals(ctx context.Context) error { qctx, cancel := context.WithTimeout(ctx, 15*time.Second) defer cancel() var allTime, today, totalKills int64 // Each query degrades to 0 on error, mirroring the Python try/except blocks. _ = s.pool.QueryRow(qctx, "SELECT COALESCE(SUM(total_rares), 0) FROM rare_stats").Scan(&allTime) _ = s.pool.QueryRow(qctx, "SELECT COUNT(*) FROM rare_events WHERE timestamp >= CURRENT_DATE").Scan(&today) _ = s.pool.QueryRow(qctx, "SELECT COALESCE(SUM(total_kills), 0) FROM char_stats").Scan(&totalKills) lastUpdated := pyISO(time.Now().UTC()) raresJSON, err := json.Marshal(map[string]any{"all_time": allTime, "today": today, "last_updated": lastUpdated}) if err != nil { return err } killsJSON, err := json.Marshal(map[string]any{"total": totalKills, "last_updated": lastUpdated}) if err != nil { return err } s.totals.set(raresJSON, killsJSON) return nil } func (s *Server) runTotalsLoop(ctx context.Context) { for { if err := s.refreshTotals(ctx); err != nil { s.log.Error("totals cache refresh failed", "err", err) } select { case <-ctx.Done(): return case <-time.After(totalsInterval): } } } func (s *Server) handleTotalRares(w http.ResponseWriter, r *http.Request) { writeRawJSON(w, s.totals.getRares()) } func (s *Server) handleTotalKills(w http.ResponseWriter, r *http.Request) { writeRawJSON(w, s.totals.getKills()) }