From defea76033f75804a45bbb650e19cb16c677295b Mon Sep 17 00:00:00 2001 From: Fuwn Date: Wed, 28 Jan 2026 03:12:23 -0800 Subject: feat: Add SSE streaming for instant page load and real-time updates New refresh_mode 'stream' eliminates blocking database queries from initial page load. Page renders instantly with skeleton UI, then hydrates via SSE. - Add SSE hub for managing client connections and broadcasting - Add /api/stream endpoint with init and update events - Add stream.html skeleton template with loading animations - Wire scheduler to broadcast on check completion - Backwards compatible: page/api modes unchanged --- internal/monitor/scheduler.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'internal/monitor') diff --git a/internal/monitor/scheduler.go b/internal/monitor/scheduler.go index 809bab5..0d584ea 100644 --- a/internal/monitor/scheduler.go +++ b/internal/monitor/scheduler.go @@ -10,16 +10,18 @@ import ( "github.com/Fuwn/kaze/internal/storage" ) -// Scheduler manages and runs all monitors +type OnCheckCallback func() + type Scheduler struct { - monitors []Monitor - monitorCfg map[string]config.MonitorConfig // Monitor configs by ID (group/name) for reset flag checks - configPath string - storage *storage.Storage - logger *slog.Logger - wg sync.WaitGroup - ctx context.Context - cancel context.CancelFunc + monitors []Monitor + monitorCfg map[string]config.MonitorConfig + configPath string + storage *storage.Storage + logger *slog.Logger + wg sync.WaitGroup + ctx context.Context + cancel context.CancelFunc + onCheckDone OnCheckCallback } // NewScheduler creates a new monitor scheduler @@ -197,6 +199,10 @@ func (s *Scheduler) executeCheck(mon Monitor) { } s.storage.RecordCheck() + + if s.onCheckDone != nil { + s.onCheckDone() + } } // runCleanup periodically cleans up old data @@ -247,11 +253,14 @@ func (s *Scheduler) runMaintenance() { } } -// GetMonitors returns all registered monitors func (s *Scheduler) GetMonitors() []Monitor { return s.monitors } +func (s *Scheduler) SetOnCheckCallback(cb OnCheckCallback) { + s.onCheckDone = cb +} + // RunCheck manually triggers a check for a specific monitor by ID (group/name format) func (s *Scheduler) RunCheck(id string) *Result { for _, mon := range s.monitors { -- cgit v1.2.3