store

package
v0.21.2 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: GPL-3.0 Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EffectiveFleetStatus added in v0.8.0

func EffectiveFleetStatus(status, lastSeen string, threshold time.Duration) string

EffectiveFleetStatus returns the status a fleet device should DISPLAY given how long ago it last checked in. It is the read-path sibling of SweepStaleFleetDevices' SQL: an "online" device whose lastSeen is older than threshold is shown as "offline" immediately, so the Fleet view is accurate between scheduler ticks without the read path ever mutating storage. lastSeen is parsed as RFC3339 (the format the heartbeat writes); a value that does not parse (e.g. AddFleetDevice's "not connected yet", or an empty last_seen) leaves the status unchanged, as does any non-"online" status.

func HashFleetKey added in v0.10.0

func HashFleetKey(key string) string

HashFleetKey returns the SHA-256 hex digest of a per-worker fleet key. The desktop fleet server only verifies inbound heartbeats and issues keys (it never calls out to devices), so a one-way hash is sufficient storage at rest.

Types

type DailyBalance added in v0.7.0

type DailyBalance struct {
	Platform string
	Currency string
	Day      string // "YYYY-MM-DD" (UTC)
	Balance  float64
}

type Deployment

type Deployment struct {
	Slug        string  `json:"slug"`
	ContainerID string  `json:"containerId"`
	Name        string  `json:"name"`
	Image       string  `json:"image"`
	Status      string  `json:"status"`
	Runtime     string  `json:"runtime"`
	CPUPercent  float64 `json:"cpuPercent"`
	MemoryMB    float64 `json:"memoryMb"`
	CreatedAt   string  `json:"createdAt"`
	UpdatedAt   string  `json:"updatedAt"`
}

type EarningsRecord

type EarningsRecord struct {
	Platform  string  `json:"platform"`
	Balance   float64 `json:"balance"`
	Currency  string  `json:"currency"`
	Error     string  `json:"error,omitempty"`
	CreatedAt string  `json:"createdAt"`
}

type FleetDevice added in v0.7.0

type FleetDevice struct {
	ID        int64    `json:"id"`
	Name      string   `json:"name"`
	Kind      string   `json:"kind"`
	Endpoint  string   `json:"endpoint"`
	OS        string   `json:"os"`
	Arch      string   `json:"arch"`
	Status    string   `json:"status"`
	Services  []string `json:"services"`
	LastSeen  string   `json:"lastSeen"`
	CreatedAt string   `json:"createdAt"`
}

type HealthScore added in v0.8.0

type HealthScore struct {
	Score         int     `json:"score"`
	UptimePercent float64 `json:"uptimePercent"`
	Samples       int     `json:"samples"`
	Restarts      int     `json:"restarts"`
	Crashes       int     `json:"crashes"`
	Stops         int     `json:"stops"`
}

HealthScore is one service's rolling health over the query window: a 0-100 Score, the uptime percentage it was blended from, and the raw event counts the score penalises. Samples is the number of health_up/health_down datapoints in the window; a service with lifecycle events but no samples yet (uptime sampling has not run) reports Samples==0 and a Score equal to its event-score, so it is not dragged to 0 merely for lacking sampling data.

type Store

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

func Open

func Open(dataDir string) (*Store, error)

func (*Store) Close

func (s *Store) Close() error

func (*Store) ConfirmFleetDeviceKey added in v0.10.0

func (s *Store) ConfirmFleetDeviceKey(kind, name string) error

ConfirmFleetDeviceKey marks a device's key confirmed — it has authenticated with its own key, so the shared bootstrap key is refused for it from now on.

func (*Store) DeleteDeployment

func (s *Store) DeleteDeployment(slug string) error

func (*Store) DeleteFleetDevice added in v0.7.0

func (s *Store) DeleteFleetDevice(id int64) error

func (*Store) FleetDeviceKeyState added in v0.10.0

func (s *Store) FleetDeviceKeyState(kind, name string) (hash string, confirmed bool, err error)

FleetDeviceKeyState returns the stored per-worker key hash and confirmed flag for the device identified by (kind, name). hash is "" when the device has no key yet (unenrolled).

func (*Store) GetCredentials

func (s *Store) GetCredentials(slug string) (map[string]string, error)

func (*Store) GetDeployment

func (s *Store) GetDeployment(slug string) (Deployment, bool, error)

func (*Store) GetServiceDetail added in v0.9.0

func (s *Store) GetServiceDetail(slug string) (string, error)

GetServiceDetail returns the stored JSON detail blob for a slug, or "" (and no error) when the slug has no detail row yet — an absent detail is a normal state, not a failure, mirroring GetCredentials' empty-map-on-ErrNoRows contract.

func (*Store) HealthScores added in v0.8.0

func (s *Store) HealthScores(days int) map[string]HealthScore

HealthScores computes a 0-100 health score per service from the runtime_events written over the last `days` days, keyed by slug. It adapts the production CashPilot health formula to the Desktop's event vocabulary:

  • event-score: start at 100, then -5 per restart (a "restarted" event), -20 per crash (any "*_error" or "missing_from_runtime"), -2 per stop (a "stopped" event); floored at 0 (and capped at 100, a no-op while subtracting).
  • uptime%: health_up / (health_up + health_down) * 100 over the window, from the per-cycle up/down sampling. Zero samples -> 0.
  • final score: once there is at least one uptime sample, blend 40% event-score with 60% uptime% (full-precision uptime, as the original does); with NO samples yet the score is the event-score alone, so a service is not punished to 0 merely because sampling has not produced data.

runtime_events.created_at is written as datetime('now') ("YYYY-MM-DD HH:MM:SS", UTC), so the window is compared against datetime('now', '-N days') in that same format — NOT the RFC3339Nano earnings uses. Only slugs with at least one event in the window appear in the returned map.

func (*Store) ListCredentialSlugs added in v0.7.0

func (s *Store) ListCredentialSlugs() []string

ListCredentialSlugs returns the slug of every service that has saved credentials, ordered by slug. collectAll unions this with the deployment set so imageless supported services (which never create a deployment row) still participate in the scheduled collection cycle.

func (*Store) ListDailyBalances added in v0.7.0

func (s *Store) ListDailyBalances(daysBack int) []DailyBalance

ListDailyBalances returns the latest successful balance (rows whose error column is empty) for each (platform, day) over the last daysBack days. The latest row per (platform, day) is chosen by MAX(id), not MAX(created_at): created_at is stored as RFC3339Nano whose variable-length fraction makes a lexicographic MAX(created_at) mis-order same-second rows (e.g. "…:00Z" sorts AFTER "…:00.5Z" because 'Z' > '.'), so the monotonic AUTOINCREMENT id is the deterministic "last written wins" key.

func (*Store) ListDeployments

func (s *Store) ListDeployments() []Deployment

func (*Store) ListFleetDevices added in v0.7.0

func (s *Store) ListFleetDevices() []FleetDevice

func (*Store) ListLatestEarnings

func (s *Store) ListLatestEarnings() []EarningsRecord

ListLatestEarnings returns the most recently written row per platform, INCLUDING error rows (the dashboard breakdown and notifications rely on the latest row even when it failed). The latest row per platform is chosen by MAX(id), not MAX(created_at): created_at is RFC3339Nano whose variable-length fraction makes a lexicographic MAX(created_at) mis-order same-second rows (e.g. "…:00Z" sorts ABOVE "…:00.5Z" because 'Z' > '.'), so the monotonic AUTOINCREMENT id is the deterministic "last written wins" key — matching the shape ListDailyBalances already uses.

func (*Store) ListServiceDetails added in v0.9.0

func (s *Store) ListServiceDetails() map[string]string

ListServiceDetails returns every stored per-service detail blob keyed by slug, so GetAppState can hand the frontend all detail documents in one read. A query or scan error yields an empty (non-nil) map rather than failing, matching the best-effort intent of the other list methods; callers can always range over the result safely.

func (*Store) PurgeOldData added in v0.8.0

func (s *Store) PurgeOldData(retentionDays int) (int64, error)

PurgeOldData deletes earnings and runtime_events rows older than the cutoff, but NEVER the most-recent earnings row per platform (so ListLatestEarnings and the dashboard breakdown keep working for a service that hasn't updated in a long time). Returns the number of rows deleted. A retentionDays <= 0 is a no-op (retention disabled).

func (*Store) RecordEvent

func (s *Store) RecordEvent(slug, event, detail string)

func (*Store) SaveCredentials

func (s *Store) SaveCredentials(slug string, values map[string]string) error

func (*Store) SaveEarnings

func (s *Store) SaveEarnings(record EarningsRecord) (EarningsRecord, error)

func (*Store) SaveServiceDetail added in v0.9.0

func (s *Store) SaveServiceDetail(slug, detailJSON string) error

SaveServiceDetail upserts a per-service JSON detail blob keyed by slug. It is a generic sidecar to the flat earnings row: any collector can stash a JSON document (e.g. the MystNodes per-node earnings breakdown) alongside its balance without widening the earnings schema. The blob is stored verbatim — the collector owns its shape and the frontend parses it — so this method never inspects detailJSON.

func (*Store) SetFleetDeviceKey added in v0.10.0

func (s *Store) SetFleetDeviceKey(kind, name, hash string) error

SetFleetDeviceKey stores a device's per-worker key hash and marks it unconfirmed (the device confirms by authenticating with the key later). It errors if the device row does not exist, so a caller never hands a client a key that was not actually persisted (which would lock that client out).

func (*Store) SweepStaleFleetDevices added in v0.8.0

func (s *Store) SweepStaleFleetDevices(offlineAfter, reapAfter time.Duration) (offlined int64, reaped int64, err error)

SweepStaleFleetDevices ages fleet devices out of the online set as heartbeats stop arriving, mirroring production CashPilot's device lifecycle: a device whose last_seen is older than offlineAfter is flipped to "offline" (the ~180s / 3-missed-heartbeat grace), and one already "offline" whose last_seen is older than reapAfter is deleted (the ~1h reap). It returns how many rows were offlined and how many were reaped.

last_seen is written by UpsertFleetHeartbeat / fleet_server as an RFC3339 timestamp WITHOUT a fractional part, so it is fixed-length and UTC; formatting the cutoffs the same way makes the lexicographic string comparison a correct chronological order. A non-timestamp placeholder such as AddFleetDevice's "not connected yet" sorts above any real cutoff, so a never-connected device is never swept.

func (*Store) UpsertDeployment

func (s *Store) UpsertDeployment(dep Deployment) error

func (*Store) UpsertFleetDevice added in v0.7.0

func (s *Store) UpsertFleetDevice(device FleetDevice) (FleetDevice, error)

func (*Store) UpsertFleetHeartbeat added in v0.7.0

func (s *Store) UpsertFleetHeartbeat(device FleetDevice) (FleetDevice, error)

Jump to

Keyboard shortcuts

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