store

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package store is simbroker's machine-global state: the set of live claims, persisted to a JSON file and guarded so that concurrent simbroker processes (CLI invocations, the MCP server, other projects) never corrupt it or race on capacity.

Correctness rules, each one load-bearing (and each verified during design):

  • Lock a dedicated sidecar file ("lock"), NEVER state.json itself. An atomic write replaces state.json's inode via rename; a flock held on the old inode would be silently stranded, giving zero mutual exclusion. The sidecar is never renamed, so its inode is stable.
  • Hold the flock across the WHOLE read-modify-write (load -> mutate -> write), not just the write — that's what makes capacity checks race-free.
  • flock auto-releases when the process dies (even on SIGKILL), so no cleanup handler is needed for crash safety.
  • flock is unreliable for intra-process exclusion, so an in-process mutex guards goroutines in the same process in addition to the cross-process flock.
  • Writes are atomic: temp file in the same dir, fsync, rename, fsync dir.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultDir

func DefaultDir() string

DefaultDir resolves the state directory: $SIMBROKER_DIR, else $XDG_STATE_HOME/simbroker, else ~/.simbroker.

Types

type Claim

type Claim struct {
	ID   string `json:"id"`
	UDID string `json:"udid"` // opaque device identity: iOS UDID, or Android AVD name
	// Class is the device class ("ios"|"android"). Added after v1; an empty
	// value (a pre-upgrade claim, or one written by an older binary) means iOS —
	// always read it through ClassOrDefault, never the bare field.
	Class      string    `json:"class,omitempty"`
	DeviceName string    `json:"device_name"`
	Label      string    `json:"label,omitempty"`
	PID        int       `json:"pid,omitempty"`       // holder pid; 0 = no liveness signal, TTL governs
	PIDStart   string    `json:"pid_start,omitempty"` // start-time fingerprint guarding against pid reuse
	Hostname   string    `json:"hostname,omitempty"`
	CreatedAt  time.Time `json:"created_at"`
	ExpiresAt  time.Time `json:"expires_at"`
	RenewedAt  time.Time `json:"renewed_at"`
}

Claim is one lease on one device.

func (Claim) ClassOrDefault

func (c Claim) ClassOrDefault() string

ClassOrDefault is the SINGLE source of truth for a claim's class: an empty Class (pre-upgrade state, or an older binary) is iOS. Every place that consults class — capacity counting, selection, reclaim — must use this so a legacy claim can never leak into another class's code path.

type State

type State struct {
	Version int     `json:"version"`
	Claims  []Claim `json:"claims"`
}

State is the whole persisted document.

type Store

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

Store is a handle to the on-disk state directory.

func New

func New(dir string) (*Store, error)

New opens (creating if needed) the state directory at dir; "" means DefaultDir.

func (*Store) ConfigPath

func (s *Store) ConfigPath() string

func (*Store) Dir

func (s *Store) Dir() string

func (*Store) StatePath

func (s *Store) StatePath() string

func (*Store) Transact

func (s *Store) Transact(fn func(*State) error) error

Transact runs fn under the exclusive lock with the current state, then persists it atomically — but only if fn actually changed something. If fn returns an error, nothing is written.

func (*Store) View

func (s *Store) View(fn func(*State) error) error

View runs fn against a consistent snapshot under the lock. It never writes.

Jump to

Keyboard shortcuts

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