game

package
v0.0.0-...-5abb9c5 Latest Latest
Warning

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

Go to latest
Published: Jan 9, 2026 License: GPL-3.0 Imports: 37 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SortScriptByTime      = SortByTime
	SortScriptByExecs     = SortByExecs
	SortScriptBySlow      = SortBySlow
	SortScriptByErrors    = SortByErrors
	SortScriptByErrorRate = SortByErrorRate
)
View Source
const (
	SortObjectByTime      = SortByTime
	SortObjectByExecs     = SortByExecs
	SortObjectBySlow      = SortBySlow
	SortObjectByErrors    = SortByErrors
	SortObjectByErrorRate = SortByErrorRate
)
View Source
const (
	SortIntervalByTime      = SortByTime
	SortIntervalByExecs     = SortByExecs
	SortIntervalBySlow      = SortBySlow
	SortIntervalByErrors    = SortByErrors
	SortIntervalByErrorRate = SortByErrorRate
)

Variables

View Source
var (
	ErrOperationAborted = fmt.Errorf("operation aborted")
)

Functions

This section is empty.

Types

type Connection

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

func (*Connection) Connect

func (c *Connection) Connect() error

func (*Connection) Process

func (c *Connection) Process() error

func (*Connection) SelectExec

func (c *Connection) SelectExec(options map[string]func() error) error

func (*Connection) SelectReturn

func (c *Connection) SelectReturn(prompt string, options []string) (string, error)

func (*Connection) TermWidth

func (c *Connection) TermWidth() int

TermWidth returns the terminal width in columns. Falls back to defaultTermWidth if PTY info is unavailable.

type ErrorCategory

type ErrorCategory string

ErrorCategory classifies the source of an error.

const (
	CategoryJS      ErrorCategory = "js"
	CategoryStorage ErrorCategory = "storage"
	CategoryTimeout ErrorCategory = "timeout"
	CategoryJSON    ErrorCategory = "json"
	CategoryOther   ErrorCategory = "other"
)

type ErrorLocation

type ErrorLocation struct {
	File   *string
	Line   *int
	Column *int
}

ErrorLocation represents where an error occurred (file:line:column). All fields are optional - nil/empty means not available.

func (ErrorLocation) String

func (l ErrorLocation) String() string

type ExecutionRecord

type ExecutionRecord struct {
	Timestamp   time.Time
	ObjectID    string
	SourcePath  string
	IntervalID  string        // Empty if not an interval event
	Duration    time.Duration // 0 for non-execution errors (boot, load)
	IsError     bool
	Category    ErrorCategory // Only set if IsError
	Location    ErrorLocation // Only set if IsError
	Message     string        // Only set if IsError (truncated)
	ImportChain []string      // For slow executions
}

ExecutionRecord captures a notable execution (error or slow) for debugging.

type Game

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

func New

func New(ctx context.Context, s *storage.Storage, firstStartup bool) (*Game, error)

New creates a new Game instance. If firstStartup is true (server directory was just created), it creates all initial source files. On all startups, it ensures fundamental objects exist (genesis, empty) so the server can function, but uses SetIfMissing to preserve any admin customizations to existing objects.

func (*Game) Context

func (g *Game) Context(ctx context.Context) structs.Context

Context creates a structs.Context that combines the given context with game time (from Queue) and server config. This is used for skill checks and other operations that need both timing and configuration.

func (*Game) GetServerConfig

func (g *Game) GetServerConfig() *structs.ServerConfig

GetServerConfig returns the server config. Thread-safe access is handled by the ServerConfig's internal mutex.

func (*Game) HandleSession

func (g *Game) HandleSession(sess ssh.Session)

func (*Game) RecoverIntervals

func (g *Game) RecoverIntervals(ctx context.Context) error

RecoverIntervals loads all intervals from persistent storage and enqueues them. Called at startup to restore interval functionality after a server restart. Uses NextFireTime to determine scheduling: - If in future: enqueue at that time (clean shutdown, timing preserved) - If in past: calculate missed intervals and enqueue for now Uses atomic Update to avoid race conditions with concurrent operations.

func (*Game) Wait

func (g *Game) Wait()

Wait blocks until all Game goroutines have stopped. The caller must cancel the context first to signal shutdown.

type GlobalJSSnapshot

type GlobalJSSnapshot struct {
	// Execution stats
	TotalExecs  uint64
	TotalTimeMs float64 // Total milliseconds of JS execution
	AvgTimeMs   float64
	TotalSlow   uint64
	SlowPercent float64
	Uptime      time.Duration
	ExecRates   RateSnapshot
	TimeRates   TimeRateSnapshot

	// Error stats
	TotalErrors  uint64
	ErrorPercent float64 // errors/executions ratio
	ByCategory   map[ErrorCategory]uint64
	ErrorRates   RateSnapshot
}

GlobalJSSnapshot contains overall JS execution and error statistics.

type IntervalExecInfo

type IntervalExecInfo struct {
	IntervalID string
	EventName  string
}

IntervalExecInfo contains interval metadata for execution recording.

type IntervalExecSnapshot

type IntervalExecSnapshot struct {
	// Identity
	IntervalID string
	ObjectID   string
	EventName  string

	// Execution stats
	Executions    uint64
	AvgTimeMs     float64
	MinTimeMs     float64
	MaxTimeMs     float64
	SlowCount     uint64
	SlowPercent   float64
	LastExecution time.Time
	ExecRates     RateSnapshot
	TimeRates     TimeRateSnapshot

	// Error stats
	Errors       uint64
	ErrorPercent float64 // errors/executions ratio
	LastError    time.Time
	ByCategory   map[ErrorCategory]uint64
	ByLocation   map[string]uint64
	ErrorRates   RateSnapshot
}

IntervalExecSnapshot contains execution and error stats for one interval.

type IntervalExecStats

type IntervalExecStats struct {
	// Execution stats
	Executions    uint64    // Total execution count
	TotalTimeNs   uint64    // Total execution time in nanoseconds
	MinTimeNs     uint64    // Minimum execution time (valid only if Executions > 0)
	MaxTimeNs     uint64    // Maximum execution time
	SlowCount     uint64    // Executions exceeding threshold
	LastExecution time.Time // Last execution timestamp
	ObjectID      string    // Owner object ID
	EventName     string    // Event name for this interval

	// Error stats
	Errors     uint64    // Total error count
	LastError  time.Time // Last error timestamp
	ByCategory map[ErrorCategory]uint64
	ByLocation map[string]uint64 // error location string -> count
	// contains filtered or unexported fields
}

IntervalExecStats tracks per-interval execution and error statistics.

type IntervalSortField

type IntervalSortField = SortField

IntervalSortField specifies how to sort interval results. Deprecated: Use SortField instead.

type InvalidUsernameError

type InvalidUsernameError struct{}

InvalidUsernameError is returned when a username fails validation.

func (InvalidUsernameError) Error

func (e InvalidUsernameError) Error() string

type JSStats

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

JSStats tracks JavaScript execution and error statistics. It monitors execution times, errors per-script/object/interval, identifies slow executions, and provides EMA-based rate tracking.

Thread safety: While the underlying caches are internally thread-safe for individual operations (Get, Set, etc.), we use an external mutex (mu) to ensure atomicity of read-modify-write sequences. Without it, concurrent goroutines could both Get() returning nil, both create new stat objects, and one would overwrite the other's modifications. The external RLock is used for read-only snapshot operations with Peek().

func NewJSStats

func NewJSStats(ctx context.Context, resolver *imports.Resolver) *JSStats

NewJSStats creates a new JSStats tracker and starts the periodic rate update loop. The loop runs until the context is cancelled.

func NewJSStatsWithTTL

func NewJSStatsWithTTL(ctx context.Context, resolver *imports.Resolver, ttl time.Duration) *JSStats

NewJSStatsWithTTL creates a new JSStats tracker with a custom TTL. This is useful for testing with shorter TTL values.

func (*JSStats) GlobalSnapshot

func (s *JSStats) GlobalSnapshot() GlobalJSSnapshot

GlobalSnapshot returns overall JS execution and error statistics.

func (*JSStats) ObjectExecSnapshot

func (s *JSStats) ObjectExecSnapshot(objectID string) *ObjectExecSnapshot

ObjectSnapshot returns stats for a specific object, or nil if not found.

func (*JSStats) RecentErrors

func (s *JSStats) RecentErrors(n int) []ExecutionRecord

RecentErrors returns the n most recent error executions, newest first.

func (*JSStats) RecentRecords

func (s *JSStats) RecentRecords(n int, filter func(*ExecutionRecord) bool) []ExecutionRecord

RecentRecords returns the n most recent notable executions (errors + slow), newest first. Use filter to select specific record types: nil for all, or a function like func(r *ExecutionRecord) bool { return r.IsError }.

func (*JSStats) RecentSlowExecutions

func (s *JSStats) RecentSlowExecutions(n int) []ExecutionRecord

RecentSlowExecutions returns the n most recent slow executions (non-errors), newest first.

func (*JSStats) RecordBootError

func (s *JSStats) RecordBootError(err error)

RecordBootError records a boot.js execution error. Boot JS doesn't go through run(), so it needs separate handling. err is the error that occurred during boot.js execution.

func (*JSStats) RecordError

func (s *JSStats) RecordError(sourcePath, objectID string, err error, duration time.Duration, intervalInfo *IntervalExecInfo)

RecordError records a JavaScript execution error with its context. This should be called from run() when JS execution fails. sourcePath is the source file path (e.g., "/user.js"). objectID is the object that executed the script. err is the error that occurred. duration is the execution time up until the error (0 if unknown, may be partial). intervalInfo is optional interval metadata (nil for non-interval events).

func (*JSStats) RecordExecution

func (s *JSStats) RecordExecution(sourcePath, objectID string, duration time.Duration, intervalInfo *IntervalExecInfo)

RecordExecution records a JavaScript execution with its duration. sourcePath is the source file path (e.g., "/user.js"). objectID is the object that executed the script. duration is the execution time. intervalInfo is optional interval metadata (nil for non-interval events).

func (*JSStats) RecordLoadError

func (s *JSStats) RecordLoadError(objectID string, err error)

RecordLoadError records a pre-run loading error (e.g., AccessObject failure). This is called from loadRun() when the object cannot be loaded before JS execution. objectID is the object that failed to load. err is the error that occurred.

func (*JSStats) RecordRecoveryError

func (s *JSStats) RecordRecoveryError(objectID, intervalID string, err error)

RecordRecoveryError records an interval recovery or re-enqueue error. These are operational errors, not JS execution errors. objectID is the object the interval belongs to. intervalID is the interval that failed recovery. err is the error that occurred.

func (*JSStats) Reset

func (s *JSStats) Reset()

Reset clears all statistics.

func (*JSStats) ScriptSnapshot

func (s *JSStats) ScriptSnapshot(sourcePath string) *ScriptSnapshot

ScriptSnapshot returns stats for a specific script, or nil if not found.

func (*JSStats) TopIntervals

func (s *JSStats) TopIntervals(by IntervalSortField, n int) []IntervalExecSnapshot

TopIntervals returns the top n intervals sorted by the specified field.

func (*JSStats) TopLocations

func (s *JSStats) TopLocations(n int) []LocationSnapshot

TopLocations returns the top n error locations by count.

func (*JSStats) TopObjects

func (s *JSStats) TopObjects(by ObjectSortField, n int) []ObjectExecSnapshot

TopObjects returns the top n objects sorted by the specified field.

func (*JSStats) TopScripts

func (s *JSStats) TopScripts(by ScriptSortField, n int) []ScriptSnapshot

TopScripts returns the top n scripts sorted by the specified field.

func (*JSStats) UpdateRates

func (s *JSStats) UpdateRates()

UpdateRates should be called periodically to update EMA rate calculations. It also triggers cleanup of expired cache entries.

type LocationSnapshot

type LocationSnapshot struct {
	Location  string
	Count     uint64
	FirstSeen time.Time
	LastSeen  time.Time
}

LocationSnapshot contains error stats for one code location.

type LocationStats

type LocationStats struct {
	Location  string    // The location string (e.g., "/user.js:42:15")
	Count     uint64    // Total error count at this location
	FirstSeen time.Time // When this location was first seen
	LastSeen  time.Time // Most recent error at this location
}

LocationStats tracks error statistics for a code location (file:line:col).

type ObjectExecSnapshot

type ObjectExecSnapshot struct {
	// Identity
	ObjectID   string
	SourcePath string

	// Execution stats
	Executions    uint64
	AvgTimeMs     float64
	MinTimeMs     float64
	MaxTimeMs     float64
	SlowCount     uint64
	SlowPercent   float64
	LastExecution time.Time
	ExecRates     RateSnapshot
	TimeRates     TimeRateSnapshot

	// Error stats
	Errors       uint64
	ErrorPercent float64 // errors/executions ratio
	LastError    time.Time
	ByCategory   map[ErrorCategory]uint64
	ByLocation   map[string]uint64
	ByScript     map[string]uint64
	ErrorRates   RateSnapshot
}

ObjectExecSnapshot contains execution and error stats for one object.

type ObjectExecStats

type ObjectExecStats struct {
	// Execution stats
	Executions    uint64    // Total execution count
	TotalTimeNs   uint64    // Total execution time in nanoseconds
	MinTimeNs     uint64    // Minimum execution time (valid only if Executions > 0)
	MaxTimeNs     uint64    // Maximum execution time
	SlowCount     uint64    // Executions exceeding threshold
	LastExecution time.Time // Last execution timestamp
	SourcePath    string    // Current source path for this object

	// Error stats
	Errors     uint64    // Total error count
	LastError  time.Time // Last error timestamp
	ByCategory map[ErrorCategory]uint64
	ByLocation map[string]uint64 // error location string -> count
	ByScript   map[string]uint64 // script path -> error count
	// contains filtered or unexported fields
}

ObjectExecStats tracks per-object execution and error statistics.

type ObjectSortField

type ObjectSortField = SortField

ObjectSortField specifies how to sort object results. Deprecated: Use SortField instead.

type RWMutex

type RWMutex interface {
	Lock()
	Unlock()
	RLock()
	RUnlock()
}

type RateSnapshot

type RateSnapshot struct {
	PerSecond float64 // Events/second, 1s EMA window
	PerMinute float64 // Events/second, 1m EMA window
	PerHour   float64 // Events/second, 1h EMA window
	PerDay    float64 // Events/second, 24h EMA window
}

RateSnapshot contains EMA rates for display. All rates are events-per-second, smoothed over different time windows. PerSecond is reactive (1s window), PerMinute is smoother (1m window), etc.

type RateStats

type RateStats struct {
	SecondRate float64 // EMA over ~1 second
	MinuteRate float64 // EMA over ~1 minute
	HourRate   float64 // EMA over ~1 hour
	DayRate    float64 // EMA over ~1 day
	// contains filtered or unexported fields
}

RateStats tracks EMA of event counts (events per second).

type ScriptSnapshot

type ScriptSnapshot struct {
	// Identity
	SourcePath string

	// Execution stats
	Executions    uint64
	AvgTimeMs     float64
	MinTimeMs     float64
	MaxTimeMs     float64
	SlowCount     uint64
	SlowPercent   float64
	LastExecution time.Time
	ImportChain   []string
	ExecRates     RateSnapshot
	TimeRates     TimeRateSnapshot

	// Error stats
	Errors       uint64
	ErrorPercent float64 // errors/executions ratio
	LastError    time.Time
	ByCategory   map[ErrorCategory]uint64
	ByLocation   map[string]uint64
	ErrorRates   RateSnapshot
}

ScriptSnapshot contains stats for one script path.

type ScriptSortField

type ScriptSortField = SortField

ScriptSortField specifies how to sort script results. Deprecated: Use SortField instead.

type ScriptStats

type ScriptStats struct {
	// Execution stats
	Executions    uint64    // Total execution count
	TotalTimeNs   uint64    // Total execution time in nanoseconds
	MinTimeNs     uint64    // Minimum execution time (valid only if Executions > 0)
	MaxTimeNs     uint64    // Maximum execution time
	SlowCount     uint64    // Executions exceeding threshold
	LastExecution time.Time // Last execution timestamp

	// Error stats
	Errors     uint64    // Total error count
	LastError  time.Time // Last error timestamp
	ByCategory map[ErrorCategory]uint64
	ByLocation map[string]uint64 // error location string -> count
	// contains filtered or unexported fields
}

ScriptStats tracks per-script (source path) execution and error statistics.

type SortField

type SortField int

SortField is a unified sort field type for scripts, objects, and intervals. All entity types use the same sort criteria (time, execs, slow, errors, error rate).

const (
	SortByTime      SortField = iota // Total execution time
	SortByExecs                      // Execution count
	SortBySlow                       // Slow count
	SortByErrors                     // Error count
	SortByErrorRate                  // Error percentage
)

type Switchboard

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

Switchboard manages debug console connections from wizards to objects. It provides a Writer for each object that broadcasts to all attached terminals. Also maintains a ring buffer of recent messages per object.

func NewSwitchboard

func NewSwitchboard(ctx context.Context) *Switchboard

NewSwitchboard creates a new console switchboard and starts the cleanup goroutine. The cleanup goroutine runs until ctx is cancelled.

func (*Switchboard) Attach

func (s *Switchboard) Attach(objectID string, t *term.Terminal)

Attach connects a terminal to receive debug output from an object. Nil terminals are ignored.

func (*Switchboard) Detach

func (s *Switchboard) Detach(objectID string, t *term.Terminal)

Detach disconnects a terminal from an object's debug output.

func (*Switchboard) GetBuffered

func (s *Switchboard) GetBuffered(objectID string) [][]byte

GetBuffered returns all non-expired buffered messages for an object in chronological order. Returns nil if no messages are buffered or all have expired. Also cleans up the buffer entry if all messages have expired.

func (*Switchboard) IsAttached

func (s *Switchboard) IsAttached(objectID string, t *term.Terminal) bool

IsAttached returns true if the terminal is attached to the object.

func (*Switchboard) Writer

func (s *Switchboard) Writer(objectID string) *SwitchboardWriter

Writer returns an io.Writer that broadcasts to all terminals attached to the object. Failed writes automatically detach the terminal.

Note: Due to lock-free I/O (to avoid deadlocks with slow terminals), a terminal may receive one additional write after being detached if a Write() was already in progress when Detach() was called.

type SwitchboardWriter

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

SwitchboardWriter broadcasts writes to all terminals attached to an object. Must be created via Switchboard.Writer(), not instantiated directly.

func (*SwitchboardWriter) Write

func (w *SwitchboardWriter) Write(b []byte) (int, error)

Write implements io.Writer. For broadcast semantics, this always returns (len(b), nil) as long as the write is attempted, even if some terminals fail. Failed terminals are automatically detached from the switchboard. All messages are also stored in the ring buffer for later retrieval.

type TimeRateSnapshot

type TimeRateSnapshot struct {
	PerSecond float64 // JS sec/wall sec, 1s EMA window
	PerMinute float64 // JS sec/wall sec, 1m EMA window
	PerHour   float64 // JS sec/wall sec, 1h EMA window
	PerDay    float64 // JS sec/wall sec, 24h EMA window
}

TimeRateSnapshot contains EMA of execution time rates. All rates are JS-seconds per wall-second, smoothed over different time windows.

type TimeRateStats

type TimeRateStats struct {
	SecondRate float64 // Seconds of JS per second of wall time
	MinuteRate float64 // Seconds of JS per minute of wall time
	HourRate   float64 // Seconds of JS per hour of wall time
	DayRate    float64 // Seconds of JS per day of wall time
	// contains filtered or unexported fields
}

TimeRateStats tracks EMA of execution time (seconds of JS per second of wall time). This is distinct from RateStats which tracks event counts.

Jump to

Keyboard shortcuts

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