Documentation
¶
Index ¶
- Constants
- Variables
- func MappingsFromConfig(cfg *config.Instance) []database.Mapping
- func NormalizeID(uid string) string
- type UserDB
- func (db *UserDB) ActivateProfile(profileID string, lastUsedAt int64) error
- func (db *UserDB) AddHistory(entry *database.HistoryEntry) error
- func (db *UserDB) AddInboxMessage(msg *database.InboxMessage) (*database.InboxMessage, error)
- func (db *UserDB) AddMapping(m *database.Mapping) error
- func (db *UserDB) AddMediaHistory(entry *database.MediaHistoryEntry) (int64, error)
- func (db *UserDB) Allocate() error
- func (db *UserDB) BackfillMediaHistoryUUIDs() (int64, error)
- func (db *UserDB) Backup(reason string, manual bool) (database.BackupInfo, error)
- func (db *UserDB) BackupForTransfer(ctx context.Context, reason string) (database.BackupInfo, func() error, error)
- func (db *UserDB) CleanupHistory(retentionDays int) (int64, error)
- func (db *UserDB) CleanupMediaHistory(retentionDays int, requireSynced bool) (int64, error)
- func (db *UserDB) ClearCorruptMarker() error
- func (db *UserDB) Close() error
- func (db *UserDB) CloseHangingMediaHistory() error
- func (db *UserDB) CloseMediaHistory(dbid int64, endTime time.Time, playTime int) error
- func (db *UserDB) CountClients() (int, error)
- func (db *UserDB) CreateClient(c *database.Client) error
- func (db *UserDB) CreateProfile(p *database.Profile) error
- func (db *UserDB) DeleteAllInboxMessages() (int64, error)
- func (db *UserDB) DeleteClient(clientID string) error
- func (db *UserDB) DeleteDeviceState(key string) error
- func (db *UserDB) DeleteInboxMessage(id int64) error
- func (db *UserDB) DeleteMapping(id int64) error
- func (db *UserDB) DeleteMediaUserData(systemID, path string) error
- func (db *UserDB) DeleteProfile(profileID string) error
- func (db *UserDB) EnsureRecentBackup(maxAge time.Duration) (database.BackupInfo, bool, error)
- func (db *UserDB) GetAllMappings() ([]database.Mapping, error)
- func (db *UserDB) GetClientByToken(authToken string) (*database.Client, error)
- func (db *UserDB) GetDBPath() string
- func (db *UserDB) GetDeviceState(key string) (value string, found bool, err error)
- func (db *UserDB) GetEnabledMappings() ([]database.Mapping, error)
- func (db *UserDB) GetHistory(lastID int64) ([]database.HistoryEntry, error)
- func (db *UserDB) GetInboxMessages() ([]database.InboxMessage, error)
- func (db *UserDB) GetLatestMediaHistory() (database.MediaHistoryEntry, bool, error)
- func (db *UserDB) GetMapping(id int64) (database.Mapping, error)
- func (db *UserDB) GetMediaHistory(systemIDs []string, lastID int64, limit int) ([]database.MediaHistoryEntry, error)
- func (db *UserDB) GetMediaHistoryIdentityBackfillBatch(afterDBID int64, policyVersion int, limit int) ([]database.MediaHistoryEntry, error)
- func (db *UserDB) GetMediaHistorySyncBatch(after time.Time, afterDBID int64, limit int) ([]database.MediaHistoryEntry, error)
- func (db *UserDB) GetMediaHistoryTop(systemIDs []string, since *time.Time, limit int) ([]database.MediaHistoryTopEntry, error)
- func (db *UserDB) GetMediaUserData(systemID, path string) (database.MediaUserData, bool, error)
- func (db *UserDB) GetProfile(profileID string) (*database.Profile, error)
- func (db *UserDB) GetProfileBySwitchID(switchID string) (*database.Profile, error)
- func (db *UserDB) GetSupportedZapLinkHosts() ([]string, error)
- func (db *UserDB) GetZapLinkCache(url string) (string, error)
- func (db *UserDB) GetZapLinkHost(host string) (found, zapScript bool, err error)
- func (db *UserDB) HealTimestamps(bootUUID string, trueBootTime time.Time) (int64, error)
- func (db *UserDB) IntegrityReport() []string
- func (db *UserDB) IsMarkedCorrupt() bool
- func (db *UserDB) ListBackups() ([]database.BackupInfo, error)
- func (db *UserDB) ListClients() ([]database.Client, error)
- func (db *UserDB) ListMediaUserData() ([]database.MediaUserData, error)
- func (db *UserDB) ListProfiles() ([]database.Profile, error)
- func (db *UserDB) MarkCorrupt(reason string)
- func (db *UserDB) MarkMediaHistorySynced(refs []database.MediaHistorySyncRef, syncedAt time.Time) error
- func (db *UserDB) MigrateUp() error
- func (db *UserDB) NoteCorruption(err error) bool
- func (db *UserDB) Open() error
- func (db *UserDB) PruneExpiredZapLinkHosts(olderThan time.Duration) (int64, error)
- func (db *UserDB) RecoverFromCorruption() (database.RestoreInfo, error)
- func (db *UserDB) ReplaceAllClients(clients []database.Client) error
- func (db *UserDB) ResetMediaHistorySyncAfter(watermark *time.Time) error
- func (db *UserDB) RestoreBackup(name string) (database.RestoreInfo, error)
- func (db *UserDB) SetDeviceState(key, value string) error
- func (db *UserDB) SetMediaUserFavorite(systemID, path string, favorite bool) error
- func (db *UserDB) SetMediaUserLauncherOverride(systemID, path, launcherID string) error
- func (db *UserDB) SetMediaUserSnapshot(systemID, path, mediaName string, tags []string) error
- func (db *UserDB) SetSQLForTesting(ctx context.Context, sqlDB *sql.DB, platform platforms.Platform) error
- func (db *UserDB) SumMediaPlayTimeForDay(dayStart time.Time) (int64, error)
- func (db *UserDB) SumMediaPlayTimeForDayByProfile(dayStart time.Time, profileID string) (int64, error)
- func (db *UserDB) Truncate() error
- func (db *UserDB) UnsafeGetSQLDb() *sql.DB
- func (db *UserDB) UpdateClientLastSeen(authToken string, lastSeenAt int64) error
- func (db *UserDB) UpdateMapping(id int64, m *database.Mapping) error
- func (db *UserDB) UpdateMediaHistoryIdentity(dbid int64, identity *database.MediaIdentity) (bool, error)
- func (db *UserDB) UpdateMediaHistoryTime(dbid int64, playTime int) error
- func (db *UserDB) UpdateProfile(p *database.Profile) error
- func (db *UserDB) UpdateZapLinkCache(url, zapscript string) error
- func (db *UserDB) UpdateZapLinkHost(host string, zapscript int) error
- func (db *UserDB) UpsertMediaUserData(data *database.MediaUserData) error
- func (db *UserDB) Vacuum() error
Constants ¶
const ( MappingTypeID = "id" MappingTypeValue = "value" MappingTypeData = "data" MatchTypeExact = "exact" MatchTypePartial = "partial" MatchTypeRegex = "regex" LegacyMappingTypeUID = "uid" LegacyMappingTypeText = "text" )
Variables ¶
var ( // ErrProfileNotFound is returned when a profile lookup matches no row. ErrProfileNotFound = errors.New("profile not found") // ErrLastProfileAdmin is returned when an operation would remove the // final administrator profile. ErrLastProfileAdmin = errors.New("cannot remove the last admin profile") )
var AllowedMappingTypes = []string{ MappingTypeID, MappingTypeValue, MappingTypeData, }
var AllowedMatchTypes = []string{ MatchTypeExact, MatchTypePartial, MatchTypeRegex, }
var ErrConnDrainTimeout = errors.New("timed out waiting for user database queries to finish")
ErrConnDrainTimeout is returned when queries are still running after the connection pool has been closed and the drain deadline has passed.
var ErrInvalidAuthToken = errors.New("auth token must not contain ':'")
ErrInvalidAuthToken rejects ':' in auth tokens (AAD uses `<token>:ws`; also enforced by SQL CHECK).
var ErrLastClientAdmin = errors.New("cannot delete the last admin client")
ErrLastClientAdmin is returned when deleting the final admin client.
var ErrNullSQL = errors.New("UserDB is not connected")
Functions ¶
func MappingsFromConfig ¶ added in v2.15.0
MappingsFromConfig converts the file-based mappings loaded into config into the database.Mapping shape used for matching and API responses. The returned mappings are always enabled and carry no database ID, since they originate from the mappings folder rather than UserDB.
func NormalizeID ¶
Types ¶
type UserDB ¶
type UserDB struct {
// contains filtered or unexported fields
}
func (*UserDB) ActivateProfile ¶ added in v2.16.0
ActivateProfile atomically records profile use and persists it as active.
func (*UserDB) AddHistory ¶
func (db *UserDB) AddHistory(entry *database.HistoryEntry) error
func (*UserDB) AddInboxMessage ¶ added in v2.8.0
func (db *UserDB) AddInboxMessage(msg *database.InboxMessage) (*database.InboxMessage, error)
func (*UserDB) AddMediaHistory ¶ added in v2.7.0
func (db *UserDB) AddMediaHistory(entry *database.MediaHistoryEntry) (int64, error)
AddMediaHistory adds a new media history entry and returns the DBID.
func (*UserDB) BackfillMediaHistoryUUIDs ¶ added in v2.16.0
BackfillMediaHistoryUUIDs assigns stable session UUIDs to legacy MediaHistory rows written before UUIDs existed. Existing timestamps remain unchanged.
func (*UserDB) BackupForTransfer ¶ added in v2.16.0
func (db *UserDB) BackupForTransfer( ctx context.Context, reason string, ) (database.BackupInfo, func() error, error)
BackupForTransfer creates a validated portable snapshot without paired-client credentials. Cleanup owns the private temporary directory and is safe to call more than once.
func (*UserDB) CleanupHistory ¶ added in v2.7.0
func (*UserDB) CleanupMediaHistory ¶ added in v2.7.0
CleanupMediaHistory removes media history older than the retention period. When requireSynced is true, only server-acknowledged versions are removed.
func (*UserDB) ClearCorruptMarker ¶ added in v2.15.0
func (*UserDB) CloseHangingMediaHistory ¶ added in v2.7.0
CloseHangingMediaHistory closes any media history entries left open from unclean shutdowns. It sets EndTime = StartTime + PlayTime for entries where EndTime is NULL.
func (*UserDB) CloseMediaHistory ¶ added in v2.7.0
CloseMediaHistory finalizes a media history entry with end time and final play time.
func (*UserDB) CountClients ¶ added in v2.11.0
func (*UserDB) CreateClient ¶ added in v2.11.0
func (*UserDB) CreateProfile ¶ added in v2.16.0
func (*UserDB) DeleteAllInboxMessages ¶ added in v2.8.0
func (*UserDB) DeleteClient ¶ added in v2.11.0
func (*UserDB) DeleteDeviceState ¶ added in v2.16.0
func (*UserDB) DeleteInboxMessage ¶ added in v2.8.0
func (*UserDB) DeleteMapping ¶
func (*UserDB) DeleteMediaUserData ¶ added in v2.15.0
DeleteMediaUserData removes the user-data row for (SystemID, Path). Deleting a row that does not exist is not an error.
func (*UserDB) DeleteProfile ¶ added in v2.16.0
DeleteProfile removes a profile. If the profile is the device's active profile, the active-profile device state is cleared in the same transaction.
func (*UserDB) EnsureRecentBackup ¶ added in v2.15.0
func (*UserDB) GetClientByToken ¶ added in v2.11.0
func (*UserDB) GetDeviceState ¶ added in v2.16.0
GetDeviceState returns the value for key and whether it exists.
func (*UserDB) GetEnabledMappings ¶
func (*UserDB) GetHistory ¶
func (db *UserDB) GetHistory(lastID int64) ([]database.HistoryEntry, error)
func (*UserDB) GetInboxMessages ¶ added in v2.8.0
func (db *UserDB) GetInboxMessages() ([]database.InboxMessage, error)
func (*UserDB) GetLatestMediaHistory ¶ added in v2.14.0
func (db *UserDB) GetLatestMediaHistory() (database.MediaHistoryEntry, bool, error)
GetLatestMediaHistory retrieves the most recent media history entry with no enrichment.
func (*UserDB) GetMediaHistory ¶ added in v2.7.0
func (db *UserDB) GetMediaHistory(systemIDs []string, lastID int64, limit int) ([]database.MediaHistoryEntry, error)
GetMediaHistory retrieves media history entries with pagination and optional system filtering.
func (*UserDB) GetMediaHistoryIdentityBackfillBatch ¶ added in v2.16.1
func (db *UserDB) GetMediaHistoryIdentityBackfillBatch( afterDBID int64, policyVersion int, limit int, ) ([]database.MediaHistoryEntry, error)
GetMediaHistoryIdentityBackfillBatch returns legacy history rows whose scanner identity is absent or older than policyVersion. Future-policy rows are never selected for downgrade.
func (*UserDB) GetMediaHistorySyncBatch ¶ added in v2.16.0
func (db *UserDB) GetMediaHistorySyncBatch( after time.Time, afterDBID int64, limit int, ) ([]database.MediaHistoryEntry, error)
GetMediaHistorySyncBatch returns unsynced rows after the local (after, afterDBID) cursor in (UpdatedAt, DBID) order. Mutations clear SyncedAt, so acknowledged rows do not repeat and unreliable-clock rows remain eligible regardless of the server's timestamp watermark. Rows without a session UUID are excluded; startup backfills legacy rows first.
func (*UserDB) GetMediaHistoryTop ¶ added in v2.10.0
func (db *UserDB) GetMediaHistoryTop( systemIDs []string, since *time.Time, limit int, ) ([]database.MediaHistoryTopEntry, error)
GetMediaHistoryTop returns aggregated media history grouped by SystemID+MediaName, sorted by total play time descending.
func (*UserDB) GetMediaUserData ¶ added in v2.15.0
GetMediaUserData returns the user-data row for a media path. The bool is false when no row exists for the (systemID, path) key, in which case the media has no favourite or launcher-override intent recorded.
func (*UserDB) GetProfile ¶ added in v2.16.0
func (*UserDB) GetProfileBySwitchID ¶ added in v2.16.0
func (*UserDB) GetSupportedZapLinkHosts ¶ added in v2.8.0
func (*UserDB) GetZapLinkHost ¶
func (*UserDB) HealTimestamps ¶ added in v2.7.0
HealTimestamps corrects timestamps for records created with unreliable clocks (MiSTer boot without NTP). When NTP syncs, this reconstructs correct timestamps using: TrueStartTime = TrueBootTime + MonotonicStart
func (*UserDB) IntegrityReport ¶ added in v2.15.0
func (*UserDB) IsMarkedCorrupt ¶ added in v2.15.0
func (*UserDB) ListBackups ¶ added in v2.15.0
func (db *UserDB) ListBackups() ([]database.BackupInfo, error)
func (*UserDB) ListClients ¶ added in v2.11.0
func (*UserDB) ListMediaUserData ¶ added in v2.15.0
func (db *UserDB) ListMediaUserData() ([]database.MediaUserData, error)
ListMediaUserData returns every user-data row, used by the reindex re-apply step to re-materialize the media.db projection.
func (*UserDB) ListProfiles ¶ added in v2.16.0
func (*UserDB) MarkCorrupt ¶ added in v2.15.0
func (*UserDB) MarkMediaHistorySynced ¶ added in v2.16.0
func (db *UserDB) MarkMediaHistorySynced(refs []database.MediaHistorySyncRef, syncedAt time.Time) error
MarkMediaHistorySynced stamps SyncedAt only when each row still matches the uploaded version. Concurrent mutations advance UpdatedAt and remain unsynced.
func (*UserDB) NoteCorruption ¶ added in v2.15.0
func (*UserDB) PruneExpiredZapLinkHosts ¶ added in v2.8.0
func (*UserDB) RecoverFromCorruption ¶ added in v2.15.0
func (db *UserDB) RecoverFromCorruption() (database.RestoreInfo, error)
func (*UserDB) ReplaceAllClients ¶ added in v2.16.0
ReplaceAllClients atomically replaces every paired client row. Device backup restore uses this to carry the destination's paired clients across a restored user database, since portable snapshots are created without client rows.
func (*UserDB) ResetMediaHistorySyncAfter ¶ added in v2.16.0
ResetMediaHistorySyncAfter clears local acknowledgements newer than the server watermark so restored or reset server state is uploaded again. A nil watermark means the server has no sessions and resets every local row.
func (*UserDB) RestoreBackup ¶ added in v2.15.0
func (db *UserDB) RestoreBackup(name string) (database.RestoreInfo, error)
func (*UserDB) SetDeviceState ¶ added in v2.16.0
func (*UserDB) SetMediaUserFavorite ¶ added in v2.15.0
SetMediaUserFavorite records (or clears) the favourite intent for a media path without disturbing any launcher override on the same row. The write is a column-scoped upsert plus a conditional delete, run in one transaction so two concurrent edits to the same path (e.g. a favourite toggle and a launcher override) cannot read-modify-write over each other.
func (*UserDB) SetMediaUserLauncherOverride ¶ added in v2.15.0
SetMediaUserLauncherOverride records (or clears, when launcherID is empty) the launcher-override intent for a media path without disturbing the favourite flag on the same row. See SetMediaUserFavorite for the concurrency guarantee.
func (*UserDB) SetMediaUserSnapshot ¶ added in v2.16.0
SetMediaUserSnapshot records a successfully resolved scanner identity snapshot on an existing user-data row. It never inserts: a snapshot without user intent (favourite/override) is meaningless. Empty tags are significant and replace stale tags; callers must skip this method when lookup fails.
func (*UserDB) SetSQLForTesting ¶
func (db *UserDB) SetSQLForTesting(ctx context.Context, sqlDB *sql.DB, platform platforms.Platform) error
SetSQLForTesting allows injection of a sql.DB instance for testing purposes. This method should only be used in tests to set up in-memory databases.
func (*UserDB) SumMediaPlayTimeForDay ¶ added in v2.15.0
SumMediaPlayTimeForDay returns the total seconds of completed play-time that overlaps with the day starting at dayStart. Sessions that span midnight are pro-rated: only the portion after dayStart is counted. The currently-active session (EndTime IS NULL) is excluded; callers add it separately.
func (*UserDB) SumMediaPlayTimeForDayByProfile ¶ added in v2.16.0
func (db *UserDB) SumMediaPlayTimeForDayByProfile(dayStart time.Time, profileID string) (int64, error)
SumMediaPlayTimeForDayByProfile is SumMediaPlayTimeForDay scoped to history attributed to a single profile. History with no profile (the shared profile) is counted by SumMediaPlayTimeForDay, which sums all rows: shared limits are device-level, so deactivating a profile must not grant a fresh daily allowance.
func (*UserDB) UnsafeGetSQLDb ¶
func (*UserDB) UpdateClientLastSeen ¶ added in v2.11.0
func (*UserDB) UpdateMediaHistoryIdentity ¶ added in v2.16.0
func (db *UserDB) UpdateMediaHistoryIdentity(dbid int64, identity *database.MediaIdentity) (bool, error)
UpdateMediaHistoryIdentity stores a complete scanner identity snapshot and reports whether this policy version changed the history row.
func (*UserDB) UpdateMediaHistoryTime ¶ added in v2.7.0
UpdateMediaHistoryTime updates only the PlayTime for currently playing media.
func (*UserDB) UpdateProfile ¶ added in v2.16.0
func (*UserDB) UpdateZapLinkCache ¶
func (*UserDB) UpdateZapLinkHost ¶
func (*UserDB) UpsertMediaUserData ¶ added in v2.15.0
func (db *UserDB) UpsertMediaUserData(data *database.MediaUserData) error
UpsertMediaUserData inserts or updates the user-data row for (SystemID, Path). CreatedAt is set on insert only; UpdatedAt is set on every write. A row with no favourite and no launcher override carries no user intent, so it is deleted rather than persisted (keeping ListMediaUserData and the backfill guard honest).