Documentation
¶
Overview ¶
Package activity provides concurrent-safe activity and alert tracking for the subflux UI status indicator.
Index ¶
- Constants
- type ActivitySource
- type Alert
- type AlertKind
- type AlertLevel
- type AlertLog
- func (al *AlertLog) AddAlert(source, message string, kind AlertKind, level AlertLevel, ttl time.Duration)
- func (al *AlertLog) AlertsUnsafe() []Alert
- func (al *AlertLog) AppendAlert(a Alert)
- func (al *AlertLog) Dismiss(id int) bool
- func (al *AlertLog) DismissBySource(source string)
- func (al *AlertLog) Lock()
- func (al *AlertLog) RLock()
- func (al *AlertLog) RUnlock()
- func (al *AlertLog) Record(source, message string)
- func (al *AlertLog) RecordInfo(message string)
- func (al *AlertLog) RecordPersistent(source, message string)
- func (al *AlertLog) RecordWarn(source, message string)
- func (al *AlertLog) Unlock()
- func (al *AlertLog) VisibleAlerts() []Alert
- type Entry
- type Log
- func (a *Log) ActiveScan(scope ScanScope) (string, bool)
- func (a *Log) Cancel(id string) bool
- func (a *Log) Dismiss(id string)
- func (a *Log) End(id string)
- func (a *Log) Entries() []Entry
- func (a *Log) Fail(id string)
- func (a *Log) FinishCancelled(id string)
- func (a *Log) Get(id string) (Entry, bool)
- func (a *Log) IsCancelled(id string) bool
- func (a *Log) Progress(id string, current, total int, detail string)
- func (a *Log) PruneCompleted(maxAge time.Duration)
- func (a *Log) SetQueued(id string, queued bool)
- func (a *Log) Start(action, detail string, source ActivitySource) string
- func (a *Log) StartScan(action, detail string, source ActivitySource, scope ScanScope, role auth.Role) (id string, existing bool)
- type Outcome
- type ScanKind
- type ScanScope
- type StopRegistry
- type StopResult
- type WarnRecorder
Constants ¶
const DefaultPruneAge = 15 * time.Minute
DefaultPruneAge is the duration after which completed activities are pruned.
const TransientAlertTTL = 1 * time.Hour
TransientAlertTTL is the default TTL for transient alerts.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ActivitySource ¶
type ActivitySource string //nolint:revive // stutters but renaming breaks callers
ActivitySource is a typed string for activity entry source values.
const ( SourceScheduled ActivitySource = "scheduled" SourceManual ActivitySource = "manual" )
Activity source constants.
type Alert ¶
type Alert struct {
Time time.Time `json:"time"`
Level AlertLevel `json:"level"` // "error", "warn", "info"
Message string `json:"message"`
Source string `json:"source"`
Kind AlertKind `json:"kind"`
TTL time.Duration `json:"-"` // per-alert TTL override; 0 = use default
ID int `json:"id"`
Dismissed bool `json:"dismissed"`
}
Alert represents an actionable error or informational message.
type AlertLevel ¶
type AlertLevel string
AlertLevel is a typed string for alert severity levels.
const ( LevelError AlertLevel = "error" LevelWarn AlertLevel = "warn" LevelInfo AlertLevel = "info" )
Alert level constants.
type AlertLog ¶
type AlertLog struct {
// contains filtered or unexported fields
}
AlertLog tracks actionable errors for the UI.
func NewAlertLog ¶
NewAlertLog creates an AlertLog with the given max capacity.
func (*AlertLog) AddAlert ¶
func (al *AlertLog) AddAlert(source, message string, kind AlertKind, level AlertLevel, ttl time.Duration)
AddAlert appends an alert with the given level and optional TTL override.
func (*AlertLog) AlertsUnsafe ¶
AlertsUnsafe returns the internal alerts slice without copying. Caller must hold the lock.
func (*AlertLog) AppendAlert ¶
AppendAlert appends an alert directly (for test setup). Caller must hold the lock.
func (*AlertLog) DismissBySource ¶
DismissBySource dismisses all undismissed persistent alerts from a source.
func (*AlertLog) Lock ¶
func (al *AlertLog) Lock()
Lock acquires a write lock (for test manipulation).
func (*AlertLog) RLock ¶
func (al *AlertLog) RLock()
RLock acquires a read lock (for test inspection).
func (*AlertLog) RecordInfo ¶
RecordInfo adds a short-lived informational alert for scan results.
func (*AlertLog) RecordPersistent ¶
RecordPersistent adds a persistent error that requires manual dismissal.
func (*AlertLog) RecordWarn ¶
RecordWarn adds a transient warning alert.
func (*AlertLog) VisibleAlerts ¶
VisibleAlerts returns a copy of non-dismissed, non-expired alerts.
type Entry ¶
type Entry struct {
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"`
ID string `json:"id"`
Action string `json:"action"`
Detail string `json:"detail"`
Source ActivitySource `json:"source"` // "scheduled" or "manual"
Kind ScanKind `json:"kind,omitempty"`
MediaType api.MediaType `json:"media_type,omitempty"`
RequiredRole auth.Role `json:"required_role,omitempty"`
MediaID int `json:"media_id,omitempty"`
Season int `json:"season,omitempty"`
Episode int `json:"episode,omitempty"`
Current int `json:"current,omitempty"`
Total int `json:"total,omitempty"`
Done bool `json:"done"`
Queued bool `json:"queued,omitempty"`
Cancelled bool `json:"cancelled,omitempty"`
Failed bool `json:"failed,omitempty"`
Cancellable bool `json:"cancellable,omitempty"`
}
Entry represents an ongoing or recent action.
Scan entries additionally carry their structured scope (Kind, MediaType, MediaID, Season, Episode) and the role required to cancel them (RequiredRole: user for per-item scans, admin for full scans). Cancellable is a serialization-time flag merged from the StopRegistry by the activity GET handler; it is never persisted on the stored entry.
type Log ¶
type Log struct {
// contains filtered or unexported fields
}
Log tracks recent actions for the UI status indicator.
func (*Log) ActiveScan ¶ added in v0.1.148
ActiveScan returns the ID of the live (not done, not cancelled) scan entry matching scope, if any. It is the read-only half of StartScan's same-scope idempotency: endpoints guarding a start by other means (the full-scan CompareAndSwap flag) use it to answer a duplicate start with the RUNNING scan's id instead of a conflict.
func (*Log) Cancel ¶
Cancel marks a queued activity as cancelled. Returns true if found and cancelled.
func (*Log) Entries ¶
Entries returns a snapshot of all entries (for serialization). Each entry is deep-copied (see snapshotEntry): callers may mutate the result freely.
func (*Log) FinishCancelled ¶ added in v0.1.148
FinishCancelled marks an activity as TERMINALLY cancelled: Done=true, Cancelled=true, EndedAt set. This is the terminal state a user-stopped scan reaches — unlike the queued-dismiss Cancel flag alone, the entry stops rendering as running and becomes prunable.
func (*Log) Get ¶ added in v0.1.148
Get returns a snapshot copy of the entry with the given ID. The copy is deep where it matters: mutating it — including through its EndedAt pointer — never touches the log's internal state (see snapshotEntry).
func (*Log) IsCancelled ¶
IsCancelled checks if an activity has been cancelled.
func (*Log) PruneCompleted ¶
PruneCompleted removes completed activities older than maxAge.
func (*Log) Start ¶
func (a *Log) Start(action, detail string, source ActivitySource) string
Start records a new activity and returns its ID.
func (*Log) StartScan ¶ added in v0.1.148
func (a *Log) StartScan(action, detail string, source ActivitySource, scope ScanScope, role auth.Role, ) (id string, existing bool)
StartScan records a new scan activity carrying its structured scope and the role required to cancel it. Idempotent same-scope start: when an active (not done, not cancelled) entry with the same scope already exists, its ID is returned with existing=true and no new entry is created — the find-and-create pair runs under one lock so two concurrent same-scope starts cannot both create an entry.
type Outcome ¶ added in v0.1.148
type Outcome string
Outcome is the four-valued terminal outcome of a background scan runner. It replaces the former activityOK bool: a user-requested stop (cancelled) and process shutdown must never collapse into one state, and a cancelled scan must not end as success.
type ScanKind ¶ added in v0.1.148
type ScanKind string
ScanKind identifies which scan endpoint family a scan activity belongs to. Together with the media fields it forms the structured scan scope carried on activity entries (background-scans S12): the UI reconstructs running scans per scope from these fields instead of parsing human Action/Detail strings.
type ScanScope ¶ added in v0.1.148
ScanScope is the structured identity of a scan: which endpoint family started it and which media it covers. Zero fields mean "not applicable" (e.g. a full scan has only Kind). It is a parameter/matching struct; the fields are stored flat on the Entry for serialization.
type StopRegistry ¶ added in v0.1.148
type StopRegistry struct {
// contains filtered or unexported fields
}
StopRegistry tracks the live stop callbacks of running background scans, keyed by activity ID. The zero value is ready to use.
func (*StopRegistry) Cancellable ¶ added in v0.1.148
func (r *StopRegistry) Cancellable(id string) bool
Cancellable reports whether a live stop registration exists for id — the serialization-time source of the activity DTO's cancellable flag.
func (*StopRegistry) RegisterStop ¶ added in v0.1.148
func (r *StopRegistry) RegisterStop(id string, stop func()) (unregister func())
RegisterStop stores the stop callback for a running scan and returns the matching unregister func. The registration MUST be released on every terminal transition (end, fail, cancelled) or failed scans leak registrations and keep reporting cancellable; callers release via defer so every outcome path (including panics) unregisters. Unregister is idempotent.
func (*StopRegistry) RequestStop ¶ added in v0.1.148
func (r *StopRegistry) RequestStop(id string) StopResult
RequestStop asks the scan registered under id to stop gracefully. The first request invokes the stop callback AFTER releasing the registry lock (a callback must never run under any mutex) and returns StopRequested; repeated requests are idempotent (StopAlreadyStopping, callback not re-invoked). An id without a live registration — never registered, or already released by a terminal transition (the cancel-vs-end race resolves here as a no-op) — returns StopNotFound.
type StopResult ¶ added in v0.1.148
type StopResult int
StopResult is the outcome of a stop request against the registry.
const ( StopRequested StopResult = iota StopAlreadyStopping StopNotFound StopNotCancellable )
Stop request outcomes. StopNotCancellable is never returned by the registry itself (every registration is stoppable); it exists as shared vocabulary for the composing endpoint, which maps StopNotFound plus an existing terminal entry onto "not cancellable" (409).
type WarnRecorder ¶
type WarnRecorder interface {
RecordWarn(source, msg string)
}
WarnRecorder is the narrow interface for recording warning alerts. Both manualops and polling consume this single-method contract. The concrete type AlertLog satisfies it via structural typing.