sse

package
v1.23.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: GPL-2.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ActivityPayload

type ActivityPayload struct {
	Type     string          `json:"type"`
	Activity *activity.Event `json:"activity,omitempty"`
}

ActivityPayload is the message envelope for qui-owned server activity events. It is intentionally distinct from StreamPayload (whose Data is a torrent response) so the frontend's torrent-stream router never sees activity events: they are delivered as a separate named "activity" SSE event with their own handler that invalidates cached queries.

type StreamDelta added in v1.21.0

type StreamDelta struct {
	Order *[]string `json:"order,omitempty"`
}

StreamDelta describes how to reconcile a group's page-0 window against the previous frame on a "delta" event. The added or changed rows themselves ride in StreamPayload.Data.Torrents (single-instance) or Data.CrossInstanceTorrents (cross-instance); Order lists the full page key sequence and is present only when membership or ordering changed. When Order is omitted the client applies the changed rows in place at their existing positions. Keys are the torrent hash for single-instance streams and "<instanceID>:<hash>" for cross-instance streams.

Order is a pointer so a present-but-empty order (the page drained to zero rows, e.g. every match deleted) serializes as `[]` and stays distinct from an absent order. A plain `[]string` with omitempty would drop the empty slice on the wire, making a full clear indistinguishable from an aggregate-only tick and leaving the deleted rows on screen until the next keyframe.

type StreamManager

type StreamManager struct {
	// contains filtered or unexported fields
}

StreamManager owns the SSE server and keeps subscriptions in sync with qBittorrent updates.

Lock hierarchy (acquire in this order to prevent deadlock):

  1. m.mu (StreamManager.mu) - protects subscriptions, groups, loops
  2. group.mu (subscriptionGroup.mu) - protects pending queue state
  3. group.subsMu (subscriptionGroup.subsMu) - protects subscriber list

func NewStreamManager

func NewStreamManager(clientPool *qbittorrent.ClientPool, syncManager syncProvider, instanceStore *models.InstanceStore) *StreamManager

NewStreamManager constructs a manager with a configured SSE server.

func (*StreamManager) HandleMainData

func (m *StreamManager) HandleMainData(instanceID int, data *qbt.MainData)

HandleMainData implements qbittorrent.SyncEventSink.

func (*StreamManager) HandleSyncError

func (m *StreamManager) HandleSyncError(instanceID int, err error)

HandleSyncError implements qbittorrent.SyncEventSink.

func (*StreamManager) HandleTrackerHealthUpdated added in v1.22.0

func (m *StreamManager) HandleTrackerHealthUpdated(instanceID int)

HandleTrackerHealthUpdated republishes instance streams after tracker health cache refreshes.

func (*StreamManager) PrepareBatch

func (m *StreamManager) PrepareBatch(ctx context.Context, requests []streamRequest) (context.Context, []string, error)

PrepareBatch registers one or more subscribers and returns a context that carries their session ids.

func (*StreamManager) Serve

func (m *StreamManager) Serve(w http.ResponseWriter, r *http.Request)

Serve implements the HTTP handler for GET /stream and multiplexes multiple subscriptions over one SSE session.

func (*StreamManager) SetActivityHub

func (m *StreamManager) SetActivityHub(hub *activity.Hub)

SetActivityHub wires the qui-owned server-event hub and starts forwarding its events (plus keep-alive heartbeats) to connected SSE sessions. It must be called once during startup before the manager begins serving. A nil hub is ignored, leaving the activity channel disabled.

func (*StreamManager) Shutdown

func (m *StreamManager) Shutdown(ctx context.Context) error

func (*StreamManager) Stats

func (m *StreamManager) Stats() StreamStats

Stats returns a snapshot of current SSE activity and lifetime counters.

func (*StreamManager) Unregister

func (m *StreamManager) Unregister(id string)

Unregister removes and cleans up a subscriber when the HTTP connection closes.

type StreamMeta

type StreamMeta struct {
	InstanceID int       `json:"instanceId"`
	RID        int64     `json:"rid,omitempty"`
	FullUpdate bool      `json:"fullUpdate,omitempty"`
	Timestamp  time.Time `json:"timestamp"`
	// IncludeCounts asks materialization to include cached aggregate counts even
	// when the tick skips tracker hydration. Used after tracker-health cache writes
	// so dashboards receive new health totals without inline qbit work.
	IncludeCounts bool `json:"includeCounts,omitempty"`
	// LastSuccessfulSync is when the instance's data last actually updated, sourced
	// from the success-only sync clock. On stream-error frames it lets the client
	// show how stale the retained torrents are ("data from N ago") without that age
	// resetting on every failed attempt. A pointer so the zero time is omitted on the
	// wire rather than serialized as 0001-01-01 (omitempty has no effect on a struct).
	LastSuccessfulSync *time.Time `json:"lastSuccessfulSync,omitempty"`
	RetryInSeconds     int        `json:"retryInSeconds,omitempty"`
	StreamKey          string     `json:"streamKey,omitempty"`
}

StreamMeta carries lightweight metadata about the sync update.

type StreamOptions

type StreamOptions struct {
	InstanceID  int
	InstanceIDs []int
	Page        int
	Limit       int
	Sort        string
	Order       string
	Search      string
	Filters     qbittorrent.FilterOptions
}

StreamOptions captures the torrent view that the subscriber wants to keep in sync.

A subscription is single-instance when InstanceIDs is empty (keyed by InstanceID), or multi-instance (aggregated/cross-instance) when InstanceIDs holds one or more concrete instance ids. Multi-instance subscriptions are kept in sync by every one of their member instances.

type StreamPayload

type StreamPayload struct {
	Type  string                       `json:"type"`
	Data  *qbittorrent.TorrentResponse `json:"data,omitempty"`
	Delta *StreamDelta                 `json:"delta,omitempty"`
	Meta  *StreamMeta                  `json:"meta,omitempty"`
	Err   string                       `json:"error,omitempty"`
}

StreamPayload is the message envelope sent to the frontend.

type StreamStats

type StreamStats struct {
	ActiveSubscriptions int    // currently connected subscribers
	ActiveGroups        int    // distinct view groups being served
	ActiveSyncLoops     int    // per-instance sync loops running
	EventsPublished     uint64 // lifetime SSE messages successfully published
	EventsDropped       uint64 // lifetime messages dropped (marshal/publish failures)
	SyncErrors          uint64 // lifetime sync errors propagated to subscribers
}

StreamStats is a point-in-time snapshot of SSE subsystem activity. It is exported so the metrics layer can surface it (e.g. as Prometheus gauges/counters).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL