package api import ( "context" "encoding/json" "net/http" "time" "git.pengzhan.dev/haopengzhan/rsspipe/internal/ai" "git.pengzhan.dev/haopengzhan/rsspipe/internal/auth" "git.pengzhan.dev/haopengzhan/rsspipe/internal/db" "git.pengzhan.dev/haopengzhan/rsspipe/internal/events" "git.pengzhan.dev/haopengzhan/rsspipe/internal/services" "git.pengzhan.dev/haopengzhan/rsspipe/internal/worker" ) type Handler struct { db *db.DB auth *auth.AuthService bus *events.EventBus entryService *services.EntryService feedService *services.FeedService jobService *services.JobService settingsService *services.SettingsService jobEngine *worker.JobEngine aiClient *ai.Client broadcaster *SSEBroadcaster loginLimiter *RateLimiter } func NewHandler( database *db.DB, authService *auth.AuthService, bus *events.EventBus, entrySvc *services.EntryService, feedSvc *services.FeedService, jobSvc *services.JobService, settingsSvc *services.SettingsService, jobEngine *worker.JobEngine, ) *Handler { broadcaster := NewSSEBroadcaster() limiter := NewRateLimiter(5, 1*time.Minute) h := &Handler{ db: database, auth: authService, bus: bus, entryService: entrySvc, feedService: feedSvc, jobService: jobSvc, settingsService: settingsSvc, jobEngine: jobEngine, aiClient: ai.NewClient(45 * time.Second), broadcaster: broadcaster, loginLimiter: limiter, } // Wire EventBus to SSE Broadcaster if bus != nil { bus.Subscribe(events.EventJobProgress, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("job_progress", evt.Job) return nil }) bus.Subscribe(events.EventJobCompleted, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("job_completed", evt.Job) return nil }) bus.Subscribe(events.EventJobFailed, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("job_failed", evt.Job) return nil }) bus.Subscribe(events.EventPreferencesSync, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("preferences_updated", evt.DirectAttrs) return nil }) bus.Subscribe(events.EventPostCreated, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("post_created", evt.Entry) return nil }) bus.Subscribe(events.EventPostUpdated, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("post_updated", evt.Entry) return nil }) bus.Subscribe(events.EventVariantUpdated, func(ctx context.Context, evt events.Event) error { broadcaster.Broadcast("variant_updated", map[string]interface{}{ "entry": evt.Entry, "variant_key": evt.VariantKey, }) return nil }) } return h } func (h *Handler) writeJSON(w http.ResponseWriter, status int, v interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(v) } func (h *Handler) writeError(w http.ResponseWriter, status int, msg string) { h.writeJSON(w, status, map[string]string{"error": msg}) }