package client import ( "bufio" "context" "encoding/json" "fmt" "net/http" "strings" "task/internal/daemon/api" ) // SubscribeEvents streams SSE change events until ctx is cancelled. func (c *Client) SubscribeEvents(ctx context.Context, emit func(api.Event)) error { req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://daemon/v1/events", nil) if err != nil { return err } req.Header.Set(api.HeaderClient, c.kind) if c.kind == api.ClientMCP { if c.token != "" { req.Header.Set("Authorization", "Bearer "+c.token) } if c.project != "" { req.Header.Set("X-TM-Project", c.project) } } // No overall timeout for long-lived SSE. httpClient := *c.http httpClient.Timeout = 0 resp, err := httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { return fmt.Errorf("events: %s", resp.Status) } sc := bufio.NewScanner(resp.Body) for sc.Scan() { line := sc.Text() if !strings.HasPrefix(line, "data: ") { continue } var ev api.Event if err := json.Unmarshal([]byte(strings.TrimPrefix(line, "data: ")), &ev); err != nil { continue } emit(ev) } return sc.Err() }