helpers

package
v2.8.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	// ClockSourceSystem indicates the timestamp came from a system clock that appeared reliable.
	// This could be NTP, RTC, or manually set - we don't distinguish at record creation time.
	ClockSourceSystem = "system"

	// ClockSourceEpoch indicates the timestamp came from an unreliable clock (year < 2024).
	// Common on MiSTer devices that boot without RTC and haven't synced NTP yet.
	ClockSourceEpoch = "epoch"

	// ClockSourceHealed indicates the timestamp was mathematically reconstructed.
	// Original timestamp was unreliable, but was later corrected using:
	// TrueTimestamp = TrueBootTime + MonotonicOffset
	ClockSourceHealed = "healed"
)

ClockSource values indicate how a timestamp was determined

View Source
const MaxURLLength = 8192

MaxURLLength is the maximum allowed URL length for browser opening. This prevents resource exhaustion from malicious tokens with extremely long URLs.

View Source
const (
	// MinReliableYear is the earliest year considered valid for the system clock.
	// Zaparoo Core v2 was released in 2024 - any earlier date indicates an unset clock.
	MinReliableYear = 2024
)

Variables

View Source
var GlobalLauncherCache = &LauncherCache{}

GlobalLauncherCache is the singleton instance used throughout the application.

View Source
var GlobalRegexCache = NewRegexCache()

GlobalRegexCache is the singleton instance used throughout the application

View Source
var ReURI = regexp.MustCompile(`^([a-zA-Z][a-zA-Z0-9+.-]*)://(.+)$`)

Functions

func AlphaMapKeys

func AlphaMapKeys[V any](m map[string]V) []string

func CachedCompile

func CachedCompile(pattern string) (*regexp.Regexp, error)

CachedCompile compiles and caches a dynamic regex pattern. Returns error if pattern is invalid. Only use for runtime patterns - for static patterns, use package-level vars instead.

func CachedMustCompile

func CachedMustCompile(pattern string) *regexp.Regexp

CachedMustCompile compiles and caches a dynamic regex pattern. Panics if pattern is invalid. Only use for runtime patterns - for static patterns, use package-level vars instead.

func ConfigDir

func ConfigDir(pl platforms.Platform) string

func Contains

func Contains[T comparable](xs []T, x T) bool

Contains returns true if slice contains value.

func CopyFile

func CopyFile(sourcePath, destPath string, perm ...os.FileMode) error

CopyFile copies a file from sourcePath to destPath. Optional perm parameter sets file permissions (uses 0644 if not specified).

func DataDir

func DataDir(pl platforms.Platform) string

func DecodeURIIfNeeded added in v2.7.0

func DecodeURIIfNeeded(uri string) string

DecodeURIIfNeeded applies URL decoding to URIs based on their scheme - Zaparoo custom schemes (steam://, kodi-*://, etc.): uses virtualpath.ParseVirtualPathStr for full decoding - Standard web schemes (http://, https://): decodes path component only - Other schemes: returns as-is (no decoding) Returns the original URI on decoding errors (graceful fallback) Uses manual parsing to handle malformed URLs gracefully

func EnsureDirectories added in v2.7.0

func EnsureDirectories(pl platforms.Platform) error

EnsureDirectories creates the necessary directories for the application. This should be called early during startup, before InitLogging.

func EqualStringSlices added in v2.7.0

func EqualStringSlices(a, b []string) bool

EqualStringSlices compares two string slices for equality

func ExeDir

func ExeDir() string

func FilenameFromPath

func FilenameFromPath(p string) string

func FindLauncher

func FindLauncher(
	cfg *config.Instance,
	pl platforms.Platform,
	path string,
) (platforms.Launcher, error)

FindLauncher takes a path and tries to find the best possible match for a launcher, taking into account any allowlist restrictions. Returns the launcher to be used.

func GetAllLocalIPs

func GetAllLocalIPs() []string

GetAllLocalIPs returns all non-loopback private IPv4 addresses

func GetFileSize

func GetFileSize(filePath string) (int64, error)

func GetLocalIP

func GetLocalIP() string

func GetMd5Hash

func GetMd5Hash(filePath string) (string, error)

func GetPathName added in v2.8.0

func GetPathName(path string) string

GetPathName returns just the name portion (filename without extension) from a path. This is a convenience wrapper around GetPathInfo for use with platforms.DoLaunch.

func GetSerialDeviceList

func GetSerialDeviceList() ([]string, error)

func HasUserDir

func HasUserDir() (string, bool)

HasUserDir checks if a "user" directory exists next to the Zaparoo binary and returns true and the absolute path to it. This directory is used as a parent for all platform directories if it exists, for a portable install. The result is cached after the first call for better performance. This function is safe for concurrent use.

func InitLogging

func InitLogging(pl platforms.Platform, writers []io.Writer) error

func IsClockReliable added in v2.7.0

func IsClockReliable(t time.Time) bool

IsClockReliable checks if the system clock appears to be set correctly. Returns false if the clock is clearly wrong (e.g., year < 2024). This handles MiSTer's lack of RTC chip - clock often resets to epoch on boot.

func IsFalsey

func IsFalsey(s string) bool

func IsProcessRunning added in v2.7.0

func IsProcessRunning(proc *os.Process) bool

IsProcessRunning checks if a process is still running. Returns false if the process is nil or has terminated.

func IsServiceRunning

func IsServiceRunning(cfg *config.Instance) bool

func IsTruthy

func IsTruthy(s string) bool

func IsValidExtension added in v2.7.0

func IsValidExtension(ext string) bool

IsValidExtension checks if a file extension contains only valid characters Valid extensions contain only alphanumeric characters (and the leading dot) Examples: ".zip" ✓, ".tar" ✓, ".mp3" ✓, ".other thing" ✗, ".file-name" ✗

func IsZip

func IsZip(filePath string) bool

func ListZip

func ListZip(filePath string) ([]string, error)

ListZip returns a slice of all filenames in a zip file.

func LogWriter added in v2.8.0

func LogWriter() io.Writer

LogWriter returns the underlying io.Writer used by the logger. This is useful for adding additional writers (e.g., telemetry) after initialization.

func MapKeys

func MapKeys[K comparable, V any](m map[K]V) []K

MapKeys returns a list of all keys in a map.

func MatchSystemFile

func MatchSystemFile(
	cfg *config.Instance,
	pl platforms.Platform,
	systemID string,
	path string,
) bool

MatchSystemFile returns true if a given path is for a given system.

func MaybeJSON

func MaybeJSON(data []byte) bool

func NormalizePathForComparison added in v2.7.0

func NormalizePathForComparison(path string) string

NormalizePathForComparison normalizes a path for cross-platform case-insensitive comparison. Converts to forward slashes and lowercases for consistent matching across all platforms. This handles paths from databases (forward slashes) vs filepath.Join (OS-specific slashes), and ensures case-insensitive matching works for FAT32/exFAT filesystems on all platforms.

func OpenBrowser added in v2.8.0

func OpenBrowser(url string) error

OpenBrowser opens the given URL in the default web browser using xdg-open. This is a fire-and-forget operation - the browser process is started but not waited on. Only http:// and https:// URLs are accepted for security.

func PadNumber added in v2.7.0

func PadNumber(num, width int) string

PadNumber formats a number with leading zeros to the specified width. Examples:

  • PadNumber(5, 2) → "05"
  • PadNumber(42, 4) → "0042"
  • PadNumber(123, 2) → "123"

func ParseCustomLaunchers

func ParseCustomLaunchers(
	pl platforms.Platform,
	customLaunchers []config.LaunchersCustom,
) []platforms.Launcher

func PathHasPrefix added in v2.7.0

func PathHasPrefix(path, root string) bool

PathHasPrefix checks if path is within root directory, handling separator boundaries correctly. This avoids the prefix bug where "c:/roms2/game.bin" would incorrectly match root "c:/roms".

func PathIsLauncher

func PathIsLauncher(
	cfg *config.Instance,
	pl platforms.Platform,
	l *platforms.Launcher,
	path string,
) bool

PathIsLauncher returns true if a given path matches against any of the criteria defined in a launcher.

func PathToLaunchers

func PathToLaunchers(
	cfg *config.Instance,
	pl platforms.Platform,
	path string,
) []platforms.Launcher

PathToLaunchers is a reverse lookup to match a given path against all possible launchers in a platform. Returns all matched launchers.

func PlayConfiguredSound added in v2.7.0

func PlayConfiguredSound(path string, enabled bool, defaultSound []byte, soundName string)

PlayConfiguredSound plays a sound based on configuration settings. If enabled is false, no sound is played. If path is empty, plays the default embedded sound. If path is set, plays the custom sound file from that path. Errors are logged but not returned.

func RandSeq

func RandSeq(n int) (string, error)

func RandomElem

func RandomElem[T any](xs []T) (T, error)

RandomElem picks and returns a random element from a slice.

func RandomInt added in v2.7.0

func RandomInt(maxVal int) (int, error)

RandomInt returns a random integer between 0 and maxVal-1 (inclusive).

func SpawnDaemon added in v2.7.0

func SpawnDaemon(cfg *config.Instance) (cleanup func(), err error)

SpawnDaemon spawns a daemon subprocess for service isolation (e.g., TUI mode). It waits for the service API to become available and returns a cleanup function. The cleanup function sends SIGTERM and waits for graceful shutdown with timeout. Returns a no-op cleanup function if service was already running.

func TokensEqual

func TokensEqual(a, b *tokens.Token) bool

func ValidateBrowserURL added in v2.8.0

func ValidateBrowserURL(url string) error

ValidateBrowserURL checks if the URL has a valid scheme for browser opening. Only http:// and https:// URLs are accepted for security.

func WaitForAPI added in v2.7.0

func WaitForAPI(cfg *config.Instance, maxWaitTime, checkInterval time.Duration) bool

WaitForAPI waits for the service API to become available. Returns true if API became available, false if timeout reached.

func WaitForInternet

func WaitForInternet(maxTries int) bool

func YesNoPrompt

func YesNoPrompt(label string, def bool) bool

Types

type LauncherCache

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

LauncherCache provides fast O(1) launcher lookups by system ID. This replaces the expensive O(n*m) pl.Launchers() calls in hot paths.

func (*LauncherCache) GetAllLaunchers

func (lc *LauncherCache) GetAllLaunchers() []platforms.Launcher

GetAllLaunchers returns all cached launchers.

func (*LauncherCache) GetLaunchersBySystem

func (lc *LauncherCache) GetLaunchersBySystem(systemID string) []platforms.Launcher

GetLaunchersBySystem returns all launchers for a specific system ID. Returns nil if no launchers found for the system.

func (*LauncherCache) Initialize

func (lc *LauncherCache) Initialize(pl platforms.Platform, cfg *config.Instance)

Initialize builds the launcher cache from platform launchers. This should be called once at startup after custom launchers are loaded.

func (*LauncherCache) Refresh

func (lc *LauncherCache) Refresh(pl platforms.Platform, cfg *config.Instance)

Refresh rebuilds the cache with updated launcher data. This can be called via API to refresh the cache without restarting.

type PathInfo

type PathInfo struct {
	Path      string
	Filename  string
	Extension string
	Name      string
}

func GetPathInfo

func GetPathInfo(path string) PathInfo

type RegexCache

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

RegexCache provides thread-safe caching of compiled regular expressions to avoid repeated compilation overhead for dynamic/runtime patterns.

When to Use

Use CachedCompile for DYNAMIC patterns only:

  • Patterns from user configuration (config files, databases)
  • Patterns from external sources (CSV files, APIs)
  • Patterns that vary at runtime

For STATIC patterns (constant strings), use package-level variables instead:

var myPattern = regexp.MustCompile(`pattern`)  // ✅ Static pattern
re := helpers.CachedMustCompile(`pattern`)     // ❌ Don't use for static

Package-level vars provide:

  • Zero runtime overhead (no map lookups)
  • Compile-time validation (errors caught at startup)
  • Better code organization (patterns visible at top of file)

func NewRegexCache

func NewRegexCache() *RegexCache

NewRegexCache creates a new RegexCache instance

func (*RegexCache) Clear

func (rc *RegexCache) Clear()

Clear removes all cached patterns (useful for testing or memory management)

func (*RegexCache) Compile

func (rc *RegexCache) Compile(pattern string) (*regexp.Regexp, error)

Compile compiles a regex pattern and caches it for future use. If the pattern is already cached, returns the cached version. Returns an error if the pattern cannot be compiled.

func (*RegexCache) MustCompile

func (rc *RegexCache) MustCompile(pattern string) *regexp.Regexp

MustCompile compiles a regex pattern and caches it for future use. If the pattern is already cached, returns the cached version. Panics if the pattern cannot be compiled (same behavior as regexp.MustCompile).

func (*RegexCache) Size

func (rc *RegexCache) Size() int

Size returns the number of cached patterns

type Service

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

func NewService

func NewService(args ServiceArgs) (*Service, error)

func (*Service) Pid

func (s *Service) Pid() (int, error)

Pid returns the process ID of the current running service daemon.

func (*Service) Restart

func (s *Service) Restart() error

func (*Service) Running

func (s *Service) Running() bool

Running returns true if the service is running.

func (*Service) ServiceHandler

func (s *Service) ServiceHandler(cmd *string) error

func (*Service) Start

func (s *Service) Start() error

Start a new service daemon in the background.

func (*Service) Stop

func (s *Service) Stop() error

Stop the service daemon.

func (*Service) WaitForAPI added in v2.7.0

func (s *Service) WaitForAPI(cfg *config.Instance, maxWait, checkInterval time.Duration) error

WaitForAPI waits for the service API to become available with health monitoring. Returns nil if API became available, error if timeout or process crashed.

type ServiceArgs

type ServiceArgs struct {
	Platform platforms.Platform
	Entry    ServiceEntry
	NoDaemon bool
}

type ServiceEntry

type ServiceEntry func() (func() error, <-chan struct{}, error)

type SleepWakeMonitor added in v2.8.0

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

SleepWakeMonitor detects system sleep/wake events by monitoring wall clock jumps. When the system sleeps, the monotonic clock pauses but wall clock continues. On wake, the wall clock will have jumped forward significantly more than expected.

Usage:

monitor := NewSleepWakeMonitor(5 * time.Second)
for {
    if monitor.Check() {
        // Handle wake from sleep
    }
    time.Sleep(1 * time.Second)
}

func NewSleepWakeMonitor added in v2.8.0

func NewSleepWakeMonitor(threshold time.Duration) *SleepWakeMonitor

NewSleepWakeMonitor creates a monitor that detects time jumps exceeding threshold. Recommended threshold: 5 seconds for fast polling loops (allows for normal scheduling delays), or match the polling interval for slower loops.

func (*SleepWakeMonitor) Check added in v2.8.0

func (m *SleepWakeMonitor) Check() bool

Check returns true if a wake-from-sleep was likely detected since last check. Should be called regularly (e.g., every 100ms-1s) from a polling loop. Thread-safe for concurrent access.

func (*SleepWakeMonitor) Reset added in v2.8.0

func (m *SleepWakeMonitor) Reset()

Reset resets the monitor's last check time to now. Useful after handling a wake event to prevent false positives, or when resuming monitoring after a pause.

func (*SleepWakeMonitor) SetLastCheckForTesting added in v2.8.0

func (m *SleepWakeMonitor) SetLastCheckForTesting(t time.Time)

SetLastCheckForTesting sets the last check time for testing purposes. This allows tests to simulate time jumps without accessing private fields.

Directories

Path Synopsis
Package command provides an abstraction over exec.Command for testability.
Package command provides an abstraction over exec.Command for testability.
Package syncutil provides mutex primitives with optional deadlock detection.
Package syncutil provides mutex primitives with optional deadlock detection.

Jump to

Keyboard shortcuts

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