Documentation
¶
Index ¶
- Constants
- Variables
- type LauncherManager
- type PendingLaunchOverride
- type PendingWrite
- type RemoteStatus
- type State
- func (s *State) AcquireMediaLaunch() (platforms.MediaLaunchAccess, error)
- func (s *State) AcquireMediaStop(ctx context.Context) (func(), error)
- func (s *State) AcquireRestoreAccess() (func(), error)
- func (s *State) AcquireUpdateMediaGate(ctx context.Context) (func(), error)
- func (s *State) ActiveMedia() *models.ActiveMedia
- func (s *State) ActiveMediaReady() bool
- func (s *State) ActiveMediaReadyGeneration() (uint64, bool)
- func (s *State) ActiveMediaReplacedSince(gen uint64, hadMedia bool) bool
- func (s *State) ActiveProfile() *models.ActiveProfile
- func (s *State) AnyReaderWriteActive() bool
- func (s *State) BackgroundAutoPaused() bool
- func (s *State) BackgroundMedia() *models.ActiveMedia
- func (s *State) BackupCoordinator() *backupcoordinator.Coordinator
- func (s *State) BeginRestoreGate() (func(bool), error)
- func (s *State) BootUUID() string
- func (s *State) ClearPendingWrite()
- func (s *State) ConsumePendingLaunchOverride() *PendingLaunchOverride
- func (s *State) ConsumePendingWrite() *PendingWrite
- func (s *State) GetActiveCard() tokens.Token
- func (s *State) GetActivePlaylist() *playlists.Playlist
- func (s *State) GetBackgroundPlaylist() *playlists.Playlist
- func (s *State) GetContext() context.Context
- func (s *State) GetLastScanned() tokens.Token
- func (s *State) GetPendingLaunchOverride() *PendingLaunchOverride
- func (s *State) GetPendingWrite() *PendingWrite
- func (s *State) GetReader(readerID string) (readers.Reader, bool)
- func (s *State) GetSoftwareToken() *tokens.Token
- func (s *State) GetWroteToken(readerIDs ...string) *tokens.Token
- func (s *State) Inbox() *inbox.Service
- func (s *State) LauncherManager() *LauncherManager
- func (s *State) ListReaders() []readers.Reader
- func (s *State) MarkActiveMediaReady(gen uint64)
- func (s *State) MarkWrittenTagRemoved(readerIDs ...string)
- func (s *State) MediaDBRecoveryActive() bool
- func (s *State) ReaderWriteActive(readerIDs ...string) bool
- func (s *State) RemoteStatus() RemoteStatus
- func (s *State) RemoveReader(readerID string)
- func (s *State) RestartRequested() bool
- func (s *State) RestartService()
- func (s *State) RunBeforeExitHook()
- func (s *State) RunZapScriptEnabled() bool
- func (s *State) SetActiveCard(card tokens.Token)
- func (s *State) SetActiveMedia(media *models.ActiveMedia)
- func (s *State) SetActivePlaylist(playlist *playlists.Playlist)
- func (s *State) SetActiveProfile(profile *models.ActiveProfile)
- func (s *State) SetBackgroundAutoPaused(v bool)
- func (s *State) SetBackgroundMedia(media *models.ActiveMedia)
- func (s *State) SetBackgroundPlaylist(playlist *playlists.Playlist)
- func (s *State) SetBeforeExitHook(hook func())
- func (s *State) SetInbox(svc *inbox.Service)
- func (s *State) SetMediaDBRecoveryActive(active bool)
- func (s *State) SetOnMediaStartHook(hook func(*models.ActiveMedia, uint64))
- func (s *State) SetOnMediaStopHook(hook func())
- func (s *State) SetPendingLaunchOverride(pending *PendingLaunchOverride)
- func (s *State) SetPendingWrite(pending *PendingWrite)
- func (s *State) SetReader(reader readers.Reader)
- func (s *State) SetReaderWriteActive(active bool, readerIDs ...string)
- func (s *State) SetRemoteStatus(remoteState, errorCode string)
- func (s *State) SetRunZapScript(run bool)
- func (s *State) SetSoftwareToken(token *tokens.Token)
- func (s *State) SetUIEvents(service *uievents.Service)
- func (s *State) SetWroteToken(token *tokens.Token)
- func (s *State) SetWroteTokenForReader(readerID string, token *tokens.Token)
- func (s *State) StopService()
- func (s *State) TryAcquireRestoreAccess() (func(), error)
- func (s *State) UIEvents() *uievents.Service
- func (s *State) WaitForActiveMediaReady(ctx context.Context, expectedGen uint64) error
Constants ¶
const ( // RemoteStateUnknown means the poller has not reported yet. RemoteStateUnknown = "unknown" // RemoteStateDisabled means the owner has not enabled remote control. RemoteStateDisabled = "disabled" // RemoteStateUnlinked means there is no linked-account credential. RemoteStateUnlinked = "unlinked" // RemoteStateConnecting means the capability is being advertised. RemoteStateConnecting = "connecting" // RemoteStateWaiting means the device is polling for commands normally. RemoteStateWaiting = "waiting" // RemoteStateNotRemoteDevice means the server refused the poll because // this device is not the account's designated remote device. RemoteStateNotRemoteDevice = "not_remote_device" RemoteStateUnavailable = "unavailable" // RemoteStateCredentialRejected means the server rejected the device // credential; the account must be linked again. RemoteStateCredentialRejected = "credential_rejected" //nolint:gosec // G101: a state name, not a credential // RemoteStateError means the last poll failed for another reason (no // network, a server error, rate limiting). RemoteStateError = "error" )
Remote control states, as last observed by the remote operations poller. They describe why the device is or isn't reachable for remote commands right now, so the owner can see the difference between "waiting for a command" and "the server won't talk to this device".
Variables ¶
var ( ErrNoActiveMedia = errors.New("no active media") ErrActiveMediaChanged = errors.New("active media changed") ErrRestoreInProgress = errors.New("backup restore is in progress") ErrMediaLaunchInProgress = errors.New("media launch is in progress") ErrRestoreRestartRequired = errors.New("backup restore restart is pending") )
var ErrInvalidNextAction = errors.New("invalid next-action command")
ErrInvalidNextAction is returned when a one-shot next-action command (launcher override or next-card write) fails validation.
var ErrLaunchBlockedByHook = errors.New("launch blocked by before_media_start hook")
ErrLaunchBlockedByHook is returned when the before_media_start hook rejects a launch.
var ErrLaunchInProgress = errors.New("launch already in progress")
ErrLaunchInProgress is returned when a launch is attempted while another is in progress.
var ErrLaunchRequiresProfile = errors.New("launch requires an active profile")
ErrLaunchRequiresProfile is returned when profiles.require_for_launch is set and no profile is active.
var ErrRunZapScriptDisabled = errors.New("run ZapScript is disabled")
ErrRunZapScriptDisabled is returned when ZapScript execution is attempted while the user has disabled it via settings.runZapScript. Every source (local scans, mappings, remote operations) is subject to this switch — there is no bypass.
Functions ¶
This section is empty.
Types ¶
type LauncherManager ¶ added in v2.7.0
type LauncherManager struct {
// contains filtered or unexported fields
}
LauncherManager manages the lifecycle of launcher contexts across the application. It provides thread-safe access to a shared context that gets canceled whenever a new launcher starts, allowing previous launcher cleanup routines to detect when they've been superseded and should skip their cleanup actions.
func NewLauncherManager ¶ added in v2.7.0
func NewLauncherManager() *LauncherManager
func (*LauncherManager) EndLaunch ¶ added in v2.8.0
func (lm *LauncherManager) EndLaunch()
EndLaunch releases the launch lock.
func (*LauncherManager) GetContext ¶ added in v2.7.0
func (lm *LauncherManager) GetContext() context.Context
GetContext returns the current launcher context. This context will be canceled when a new launcher starts.
func (*LauncherManager) NewContext ¶ added in v2.7.0
func (lm *LauncherManager) NewContext() context.Context
NewContext cancels the current launcher context and creates a new one. This should be called when starting a new launcher to invalidate any cleanup routines from previous launchers. Returns the newly created context.
func (*LauncherManager) TryStartLaunch ¶ added in v2.8.0
func (lm *LauncherManager) TryStartLaunch() error
TryStartLaunch attempts to acquire the launch lock. Returns ErrLaunchInProgress if a launch is already in progress.
type PendingLaunchOverride ¶ added in v2.13.0
State holds the runtime state of the Zaparoo service.
LOCKING RULES: The mu mutex protects all mutable fields. To prevent deadlocks:
- Never send to channels while holding the lock (notifications, callbacks)
- Never call external methods (reader.OnMediaChange, hooks) while holding the lock
- Pattern: lock → modify state → copy needed data → unlock → send notifications
See SetActiveCard, SetActiveMedia, SetReader, RemoveReader for examples.
type PendingWrite ¶ added in v2.13.0
type RemoteStatus ¶ added in v2.17.0
type RemoteStatus struct {
LastContactAt time.Time
UpdatedAt time.Time
State string
LastErrorCode string
}
RemoteStatus is the poller's last observation. LastContactAt is the last time the server answered a poll normally; LastErrorCode is the server's error code (or a short local one) for the states that carry one.
type State ¶
type State struct {
Notifications chan<- models.Notification
// contains filtered or unexported fields
}
func (*State) AcquireMediaLaunch ¶ added in v2.16.0
func (s *State) AcquireMediaLaunch() (platforms.MediaLaunchAccess, error)
func (*State) AcquireMediaStop ¶ added in v2.16.1
AcquireMediaStop waits for in-flight media launches, then prevents another launch from starting until the returned release function is called.
func (*State) AcquireRestoreAccess ¶ added in v2.16.0
func (*State) AcquireUpdateMediaGate ¶ added in v2.17.0
AcquireUpdateMediaGate waits for in-flight launches and ActiveMedia publications, then prevents either from starting until release. The updater holds this gate from its final safety check through restart cancellation.
func (*State) ActiveMedia ¶
func (s *State) ActiveMedia() *models.ActiveMedia
func (*State) ActiveMediaReady ¶ added in v2.14.0
func (*State) ActiveMediaReadyGeneration ¶ added in v2.14.0
func (*State) ActiveMediaReplacedSince ¶ added in v2.17.0
ActiveMediaReplacedSince reports whether the active media changed since gen was captured alongside hadMedia. It is how a caller that ran before_exit tells that the hook launched or stopped media itself: stopping after that would kill what the hook started rather than the media the caller set out to exit. With nothing active when gen was taken, before_exit is a no-op and there is nothing it could have replaced.
The generation tracks media identity, not launches, so a before_exit script that relaunches media comparing equal to the outgoing media (ActiveMedia.Equal: same slot, system and slugified name) does not read as a replacement, and the caller's stop goes ahead. That is correct: media with the same content is the same media, so the caller is still stopping exactly what it asked to stop. Only a launch of something genuinely different needs protecting from the stop.
func (*State) ActiveProfile ¶ added in v2.16.0
func (s *State) ActiveProfile() *models.ActiveProfile
ActiveProfile returns a copy of the device's active profile snapshot, or nil when no profile is active.
func (*State) AnyReaderWriteActive ¶ added in v2.17.0
AnyReaderWriteActive reports whether any reader is part-way through writing a token.
ReaderWriteActive answers for one reader and defaults to the empty ID, which no production caller records under: writes are tracked per reader by Reader.ID(). A caller that wants to know whether the device is mid-write at all — the updater, before it restarts the service — has to ask about every reader, not about a reader that does not exist.
func (*State) BackgroundAutoPaused ¶ added in v2.15.0
func (*State) BackgroundMedia ¶ added in v2.15.0
func (s *State) BackgroundMedia() *models.ActiveMedia
func (*State) BackupCoordinator ¶ added in v2.16.0
func (s *State) BackupCoordinator() *backupcoordinator.Coordinator
func (*State) BeginRestoreGate ¶ added in v2.16.0
func (*State) ClearPendingWrite ¶ added in v2.13.0
func (s *State) ClearPendingWrite()
func (*State) ConsumePendingLaunchOverride ¶ added in v2.13.0
func (s *State) ConsumePendingLaunchOverride() *PendingLaunchOverride
func (*State) ConsumePendingWrite ¶ added in v2.13.0
func (s *State) ConsumePendingWrite() *PendingWrite
func (*State) GetActiveCard ¶
func (*State) GetActivePlaylist ¶
func (*State) GetBackgroundPlaylist ¶ added in v2.15.0
func (*State) GetContext ¶
func (*State) GetLastScanned ¶
func (*State) GetPendingLaunchOverride ¶ added in v2.13.0
func (s *State) GetPendingLaunchOverride() *PendingLaunchOverride
func (*State) GetPendingWrite ¶ added in v2.13.0
func (s *State) GetPendingWrite() *PendingWrite
func (*State) GetSoftwareToken ¶
func (*State) Inbox ¶ added in v2.8.0
Inbox returns the inbox service for adding system notifications.
func (*State) LauncherManager ¶ added in v2.7.0
func (s *State) LauncherManager() *LauncherManager
func (*State) ListReaders ¶
ListReaders returns all registered Reader instances.
func (*State) MarkActiveMediaReady ¶ added in v2.14.0
func (*State) MarkWrittenTagRemoved ¶ added in v2.17.0
func (*State) MediaDBRecoveryActive ¶ added in v2.17.0
MediaDBRecoveryActive reports whether automatic media database recovery is currently running.
func (*State) ReaderWriteActive ¶ added in v2.17.0
func (*State) RemoteStatus ¶ added in v2.17.0
func (s *State) RemoteStatus() RemoteStatus
RemoteStatus returns the poller's last observation. State is empty until the poller has reported once.
func (*State) RemoveReader ¶
RemoveReader removes a reader by its ReaderID and closes it.
func (*State) RestartRequested ¶ added in v2.10.0
RestartRequested returns true if the service shutdown was triggered by a restart request (e.g. after applying an update).
func (*State) RestartService ¶ added in v2.10.0
func (s *State) RestartService()
RestartService signals the service to shut down and restart with the new binary. Used after applying an update for graceful restart instead of os.Exit.
func (*State) RunBeforeExitHook ¶ added in v2.17.0
func (s *State) RunBeforeExitHook()
RunBeforeExitHook invokes the registered before_exit callback synchronously in the caller's goroutine. It is a no-op when no hook is registered or when another before_exit run is already in flight: at most one before_exit script runs process-wide at a time, so a script that itself stops or launches media cannot re-enter this path from any goroutine.
Callers must not hold a media gate (AcquireMediaStop, AcquireUpdateMediaGate) when calling this. The hook script may launch media, which takes the read side of the same gate and would deadlock against the exclusive holder.
func (*State) RunZapScriptEnabled ¶
func (*State) SetActiveCard ¶
func (*State) SetActiveMedia ¶
func (s *State) SetActiveMedia(media *models.ActiveMedia)
func (*State) SetActivePlaylist ¶
func (*State) SetActiveProfile ¶ added in v2.16.0
func (s *State) SetActiveProfile(profile *models.ActiveProfile)
SetActiveProfile sets or clears (nil) the device's active profile and broadcasts a profiles.active notification. The snapshot is stored by value internally so callers cannot mutate state through the pointer.
func (*State) SetBackgroundAutoPaused ¶ added in v2.15.0
func (*State) SetBackgroundMedia ¶ added in v2.15.0
func (s *State) SetBackgroundMedia(media *models.ActiveMedia)
func (*State) SetBackgroundPlaylist ¶ added in v2.15.0
func (*State) SetBeforeExitHook ¶ added in v2.17.0
func (s *State) SetBeforeExitHook(hook func())
SetBeforeExitHook registers the callback run just before active media is stopped or replaced. Pass nil to clear it.
func (*State) SetInbox ¶ added in v2.8.0
SetInbox sets the inbox service. Called during service startup after database is ready.
func (*State) SetMediaDBRecoveryActive ¶ added in v2.17.0
SetMediaDBRecoveryActive records whether automatic media database recovery currently owns the recovery workflow.
func (*State) SetOnMediaStartHook ¶
func (s *State) SetOnMediaStartHook(hook func(*models.ActiveMedia, uint64))
func (*State) SetOnMediaStopHook ¶ added in v2.15.0
func (s *State) SetOnMediaStopHook(hook func())
func (*State) SetPendingLaunchOverride ¶ added in v2.13.0
func (s *State) SetPendingLaunchOverride(pending *PendingLaunchOverride)
func (*State) SetPendingWrite ¶ added in v2.13.0
func (s *State) SetPendingWrite(pending *PendingWrite)
func (*State) SetReader ¶
SetReader registers a reader using its ReaderID as the key. If a reader with the same ReaderID exists, it is closed first.
func (*State) SetReaderWriteActive ¶ added in v2.17.0
func (*State) SetRemoteStatus ¶ added in v2.17.0
SetRemoteStatus records the poller's latest observation. A waiting state also counts as a successful contact.
func (*State) SetRunZapScript ¶
func (*State) SetSoftwareToken ¶
func (*State) SetUIEvents ¶ added in v2.16.0
SetUIEvents stores the process-wide UI event service.
func (*State) SetWroteToken ¶
func (*State) SetWroteTokenForReader ¶ added in v2.17.0
func (*State) StopService ¶
func (s *State) StopService()