From 6412362ea6e7da700f1bd1d0e55b7f9baf82023e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:32:57 +0000 Subject: [PATCH] feat: Add comprehensive docstrings to the mining package This commit adds comprehensive Go docstrings to the `pkg/mining` package, including `mining.go`, `manager.go`, `manager_interface.go`, and `xmrig.go`. The docstrings cover all public types, interfaces, functions, and methods, and include examples where appropriate to illustrate usage. This change improves the developer experience by making the code easier to understand and use. --- pkg/mining/manager.go | 71 +++++- pkg/mining/manager_interface.go | 26 +++ pkg/mining/mining.go | 397 +++++++++++++++++++++++--------- pkg/mining/xmrig.go | 116 +++++++--- 4 files changed, 448 insertions(+), 162 deletions(-) diff --git a/pkg/mining/manager.go b/pkg/mining/manager.go index 0bd462a..3affb7e 100644 --- a/pkg/mining/manager.go +++ b/pkg/mining/manager.go @@ -8,17 +8,30 @@ import ( "time" ) -// Manager handles miner lifecycle and operations +// Manager handles the lifecycle and operations of multiple miners. +// It provides a centralized way to start, stop, and manage different miner +// instances, while also collecting and exposing their performance data. +// The Manager is safe for concurrent use. type Manager struct { miners map[string]Miner - mu sync.RWMutex // Mutex to protect the miners map + mu sync.RWMutex stopChan chan struct{} waitGroup sync.WaitGroup } var _ ManagerInterface = (*Manager)(nil) -// NewManager creates a new miner manager +// NewManager creates a new miner manager. +// It initializes the manager and starts a background goroutine for periodic +// statistics collection from the miners. +// +// Example: +// +// // Create a new manager +// manager := mining.NewManager() +// defer manager.Stop() +// +// // Now you can use the manager to start and stop miners func NewManager() *Manager { m := &Manager{ miners: make(map[string]Miner), @@ -29,7 +42,33 @@ func NewManager() *Manager { return m } -// StartMiner starts a new miner with the given configuration +// StartMiner starts a new miner with the given configuration. +// It takes the miner type and a configuration object, and returns the +// created miner instance or an error if the miner could not be started. +// +// Example: +// +// // Create a new manager +// manager := mining.NewManager() +// defer manager.Stop() +// +// // Create a new configuration for the XMRig miner +// config := &mining.Config{ +// Miner: "xmrig", +// Pool: "your-pool-address", +// Wallet: "your-wallet-address", +// Threads: 4, +// TLS: true, +// } +// +// // Start the miner +// miner, err := manager.StartMiner("xmrig", config) +// if err != nil { +// log.Fatalf("Failed to start miner: %v", err) +// } +// +// // Stop the miner when you are done +// defer manager.StopMiner(miner.GetName()) func (m *Manager) StartMiner(minerType string, config *Config) (Miner, error) { m.mu.Lock() defer m.mu.Unlock() @@ -61,7 +100,9 @@ func (m *Manager) StartMiner(minerType string, config *Config) (Miner, error) { return miner, nil } -// StopMiner stops a running miner +// StopMiner stops a running miner. +// It takes the name of the miner to be stopped and returns an error if the +// miner could not be stopped. func (m *Manager) StopMiner(name string) error { m.mu.Lock() defer m.mu.Unlock() @@ -80,7 +121,8 @@ func (m *Manager) StopMiner(name string) error { return nil } -// GetMiner retrieves a miner by ID +// GetMiner retrieves a running miner by its name. +// It returns the miner instance or an error if the miner is not found. func (m *Manager) GetMiner(name string) (Miner, error) { m.mu.RLock() defer m.mu.RUnlock() @@ -93,7 +135,7 @@ func (m *Manager) GetMiner(name string) (Miner, error) { return miner, nil } -// ListMiners returns all miners +// ListMiners returns a slice of all running miners. func (m *Manager) ListMiners() []Miner { m.mu.RLock() defer m.mu.RUnlock() @@ -105,7 +147,8 @@ func (m *Manager) ListMiners() []Miner { return miners } -// ListAvailableMiners returns a list of available miners +// ListAvailableMiners returns a list of available miners that can be started. +// This provides a way to discover the types of miners supported by the manager. func (m *Manager) ListAvailableMiners() []AvailableMiner { return []AvailableMiner{ { @@ -115,7 +158,7 @@ func (m *Manager) ListAvailableMiners() []AvailableMiner { } } -// startStatsCollection starts a goroutine to periodically collect stats from active miners +// startStatsCollection starts a goroutine to periodically collect stats from active miners. func (m *Manager) startStatsCollection() { m.waitGroup.Add(1) go func() { @@ -134,7 +177,7 @@ func (m *Manager) startStatsCollection() { }() } -// collectMinerStats iterates through active miners and collects their stats +// collectMinerStats iterates through active miners and collects their stats. func (m *Manager) collectMinerStats() { m.mu.RLock() minersToCollect := make([]Miner, 0, len(m.miners)) @@ -159,7 +202,9 @@ func (m *Manager) collectMinerStats() { } } -// GetMinerHashrateHistory returns the hashrate history for a specific miner +// GetMinerHashrateHistory returns the hashrate history for a specific miner. +// It takes the name of the miner and returns a slice of hashrate points +// or an error if the miner is not found. func (m *Manager) GetMinerHashrateHistory(name string) ([]HashratePoint, error) { m.mu.RLock() defer m.mu.RUnlock() @@ -172,7 +217,9 @@ func (m *Manager) GetMinerHashrateHistory(name string) ([]HashratePoint, error) return miner.GetHashrateHistory(), nil } -// Stop stops the manager and its background goroutines +// Stop stops the manager and its background goroutines. +// It should be called when the manager is no longer needed to ensure a +// graceful shutdown of the statistics collection goroutine. func (m *Manager) Stop() { close(m.stopChan) m.waitGroup.Wait() // Wait for the stats collection goroutine to finish diff --git a/pkg/mining/manager_interface.go b/pkg/mining/manager_interface.go index ed3f1b2..46a17c4 100644 --- a/pkg/mining/manager_interface.go +++ b/pkg/mining/manager_interface.go @@ -1,12 +1,38 @@ package mining // ManagerInterface defines the interface for a miner manager. +// This interface abstracts the core functionalities of a miner manager, +// allowing for different implementations to be used interchangeably. It provides +// a standard way to manage the lifecycle of miners and retrieve their data. type ManagerInterface interface { + // StartMiner starts a new miner with the given configuration. + // It takes the miner type and a configuration object, and returns the + // created miner instance or an error if the miner could not be started. StartMiner(minerType string, config *Config) (Miner, error) + + // StopMiner stops a running miner. + // It takes the name of the miner to be stopped and returns an error if the + // miner could not be stopped. StopMiner(name string) error + + // GetMiner retrieves a running miner by its name. + // It returns the miner instance or an error if the miner is not found. GetMiner(name string) (Miner, error) + + // ListMiners returns a slice of all running miners. ListMiners() []Miner + + // ListAvailableMiners returns a list of available miners that can be started. + // This provides a way to discover the types of miners supported by the manager. ListAvailableMiners() []AvailableMiner + + // GetMinerHashrateHistory returns the hashrate history for a specific miner. + // It takes the name of the miner and returns a slice of hashrate points + // or an error if the miner is not found. GetMinerHashrateHistory(name string) ([]HashratePoint, error) + + // Stop stops the manager and its background goroutines. + // It should be called when the manager is no longer needed to ensure a + // graceful shutdown of any background processes. Stop() } diff --git a/pkg/mining/mining.go b/pkg/mining/mining.go index 4aadc45..ca9f976 100644 --- a/pkg/mining/mining.go +++ b/pkg/mining/mining.go @@ -17,184 +17,351 @@ const ( LowResHistoryRetention = 24 * time.Hour // Example: keep 24 hours of 1-minute averages ) -// Miner is the interface for a miner +// Miner defines the standard interface for a cryptocurrency miner. +// This interface abstracts the core functionalities of a miner, such as installation, +// starting, stopping, and statistics retrieval, allowing for different miner +// implementations to be used interchangeably. type Miner interface { + // Install handles the setup and installation of the miner software. + // This may include downloading binaries, creating configuration files, + // and setting up necessary permissions. Install() error + + // Uninstall removes the miner software and any related configuration files. Uninstall() error Start(config *Config) error Stop() error GetStats() (*PerformanceMetrics, error) GetName() string GetPath() string - GetBinaryPath() string // New method to get the full path to the miner executable + GetBinaryPath() string + + // CheckInstallation verifies if the miner is installed correctly and returns + // details about the installation, such as the version and path. CheckInstallation() (*InstallationDetails, error) + + // GetLatestVersion retrieves the latest available version of the miner software. GetLatestVersion() (string, error) - GetHashrateHistory() []HashratePoint // New method to get hashrate history - AddHashratePoint(point HashratePoint) // New method to add a hashrate point - ReduceHashrateHistory(now time.Time) // New method to trigger history reduction + + // GetHashrateHistory returns the recent hashrate history of the miner. + GetHashrateHistory() []HashratePoint + + // AddHashratePoint adds a new hashrate data point to the miner's history. + AddHashratePoint(point HashratePoint) + + // ReduceHashrateHistory processes the raw hashrate data, potentially + // aggregating high-resolution data into a lower-resolution format for + // long-term storage. + ReduceHashrateHistory(now time.Time) } -// InstallationDetails contains information about an installed miner +// InstallationDetails contains information about an installed miner. +// It provides a standard structure for reporting the status of a miner's +// installation, including whether it's present, its version, and its location. type InstallationDetails struct { - IsInstalled bool `json:"is_installed"` - Version string `json:"version"` - Path string `json:"path"` + // IsInstalled is true if the miner is installed, false otherwise. + IsInstalled bool `json:"is_installed"` + // Version is the detected version of the installed miner. + Version string `json:"version"` + // Path is the installation path of the miner. + Path string `json:"path"` + // MinerBinary is the name of the miner's executable file. MinerBinary string `json:"miner_binary"` } -// SystemInfo provides general system and miner installation information +// SystemInfo provides general system and miner installation information. +// This struct aggregates various details about the system's environment, +// such as operating system, architecture, and available resources, as well +// as information about installed miners. type SystemInfo struct { - Timestamp time.Time `json:"timestamp"` - OS string `json:"os"` - Architecture string `json:"architecture"` - GoVersion string `json:"go_version"` - AvailableCPUCores int `json:"available_cpu_cores"` - TotalSystemRAMGB float64 `json:"total_system_ram_gb"` + // Timestamp is the time when the system information was collected. + Timestamp time.Time `json:"timestamp"` + // OS is the operating system of the host. + OS string `json:"os"` + // Architecture is the system's hardware architecture (e.g., amd64, arm64). + Architecture string `json:"architecture"` + // GoVersion is the version of the Go runtime. + GoVersion string `json:"go_version"` + // AvailableCPUCores is the number of available CPU cores. + AvailableCPUCores int `json:"available_cpu_cores"` + // TotalSystemRAMGB is the total system RAM in gigabytes. + TotalSystemRAMGB float64 `json:"total_system_ram_gb"` + // InstalledMinersInfo is a slice containing details of all installed miners. InstalledMinersInfo []*InstallationDetails `json:"installed_miners_info"` } +// Config represents the configuration for a miner. +// This struct includes general mining parameters as well as specific options +// for different miner implementations like XMRig. It is designed to be -// Config represents the config for a miner, including XMRig specific options +// flexible and comprehensive, covering a wide range of settings from network +// and CPU configurations to logging and miscellaneous options. +// +// Example: +// +// // Create a new configuration for the XMRig miner +// config := &mining.Config{ +// Miner: "xmrig", +// Pool: "your-pool-address", +// Wallet: "your-wallet-address", +// Threads: 4, +// TLS: true, +// } type Config struct { - Miner string `json:"miner"` - Pool string `json:"pool"` - Wallet string `json:"wallet"` - Threads int `json:"threads"` - TLS bool `json:"tls"` - HugePages bool `json:"hugePages"` + // Miner is the name of the miner to be used (e.g., "xmrig"). + Miner string `json:"miner"` + // Pool is the address of the mining pool. + Pool string `json:"pool"` + // Wallet is the user's wallet address for receiving mining rewards. + Wallet string `json:"wallet"` + // Threads is the number of CPU threads to be used for mining. + Threads int `json:"threads"` + // TLS indicates whether to use a secure TLS connection to the pool. + TLS bool `json:"tls"` + // HugePages enables or disables the use of huge pages for performance optimization. + HugePages bool `json:"hugePages"` // Network options - Algo string `json:"algo,omitempty"` - Coin string `json:"coin,omitempty"` - Password string `json:"password,omitempty"` // Corresponds to -p, not --userpass - UserPass string `json:"userPass,omitempty"` // Corresponds to -O - Proxy string `json:"proxy,omitempty"` - Keepalive bool `json:"keepalive,omitempty"` - Nicehash bool `json:"nicehash,omitempty"` - RigID string `json:"rigId,omitempty"` - TLSSingerprint string `json:"tlsFingerprint,omitempty"` - Retries int `json:"retries,omitempty"` - RetryPause int `json:"retryPause,omitempty"` - UserAgent string `json:"userAgent,omitempty"` - DonateLevel int `json:"donateLevel,omitempty"` - DonateOverProxy bool `json:"donateOverProxy,omitempty"` + // Algo specifies the mining algorithm to be used. + Algo string `json:"algo,omitempty"` + // Coin specifies the cryptocurrency to be mined. + Coin string `json:"coin,omitempty"` + // Password is the pool password. + Password string `json:"password,omitempty"` + // UserPass is the username and password for the pool. + UserPass string `json:"userPass,omitempty"` + // Proxy is the address of a proxy to be used for the connection. + Proxy string `json:"proxy,omitempty"` + // Keepalive enables or disables the TCP keepalive feature. + Keepalive bool `json:"keepalive,omitempty"` + // Nicehash enables or disables Nicehash support. + Nicehash bool `json:"nicehash,omitempty"` + // RigID is the identifier of the mining rig. + RigID string `json:"rigId,omitempty"` + // TLSSingerprint is the TLS fingerprint of the pool. + TLSSingerprint string `json:"tlsFingerprint,omitempty"` + // Retries is the number of times to retry connecting to the pool. + Retries int `json:"retries,omitempty"` + // RetryPause is the pause in seconds between connection retries. + RetryPause int `json:"retryPause,omitempty"` + // UserAgent is the user agent string to be used for the connection. + UserAgent string `json:"userAgent,omitempty"` + // DonateLevel is the donation level to the miner developers. + DonateLevel int `json:"donateLevel,omitempty"` + // DonateOverProxy enables or disables donation over a proxy. + DonateOverProxy bool `json:"donateOverProxy,omitempty"` // CPU backend options - NoCPU bool `json:"noCpu,omitempty"` - CPUAffinity string `json:"cpuAffinity,omitempty"` - AV int `json:"av,omitempty"` - CPUPriority int `json:"cpuPriority,omitempty"` - CPUMaxThreadsHint int `json:"cpuMaxThreadsHint,omitempty"` - CPUMemoryPool int `json:"cpuMemoryPool,omitempty"` - CPUNoYield bool `json:"cpuNoYield,omitempty"` - HugepageSize int `json:"hugepageSize,omitempty"` - HugePagesJIT bool `json:"hugePagesJIT,omitempty"` - ASM string `json:"asm,omitempty"` - Argon2Impl string `json:"argon2Impl,omitempty"` - RandomXInit int `json:"randomXInit,omitempty"` - RandomXNoNUMA bool `json:"randomXNoNuma,omitempty"` - RandomXMode string `json:"randomXMode,omitempty"` - RandomX1GBPages bool `json:"randomX1GBPages,omitempty"` - RandomXWrmsr string `json:"randomXWrmsr,omitempty"` - RandomXNoRdmsr bool `json:"randomXNoRdmsr,omitempty"` - RandomXCacheQoS bool `json:"randomXCacheQoS,omitempty"` + // NoCPU disables the CPU backend. + NoCPU bool `json:"noCpu,omitempty"` + // CPUAffinity sets the CPU affinity for the miner. + CPUAffinity string `json:"cpuAffinity,omitempty"` + // AV is the algorithm variation. + AV int `json:"av,omitempty"` + // CPUPriority is the CPU priority for the miner. + CPUPriority int `json:"cpuPriority,omitempty"` + // CPUMaxThreadsHint is the maximum number of threads hint for the CPU. + CPUMaxThreadsHint int `json:"cpuMaxThreadsHint,omitempty"` + // CPUMemoryPool is the CPU memory pool size. + CPUMemoryPool int `json:"cpuMemoryPool,omitempty"` + // CPUNoYield enables or disables CPU yield. + CPUNoYield bool `json:"cpuNoYield,omitempty"` + // HugepageSize is the size of huge pages in kilobytes. + HugepageSize int `json:"hugepageSize,omitempty"` + // HugePagesJIT enables or disables huge pages for JIT compiled code. + HugePagesJIT bool `json:"hugePagesJIT,omitempty"` + // ASM enables or disables the ASM compiler. + ASM string `json:"asm,omitempty"` + // Argon2Impl is the Argon2 implementation. + Argon2Impl string `json:"argon2Impl,omitempty"` + // RandomXInit is the RandomX initialization value. + RandomXInit int `json:"randomXInit,omitempty"` + // RandomXNoNUMA enables or disables NUMA support for RandomX. + RandomXNoNUMA bool `json:"randomXNoNuma,omitempty"` + // RandomXMode is the RandomX mode. + RandomXMode string `json:"randomXMode,omitempty"` + // RandomX1GBPages enables or disables 1GB pages for RandomX. + RandomX1GBPages bool `json:"randomX1GBPages,omitempty"` + // RandomXWrmsr is the RandomX MSR value. + RandomXWrmsr string `json:"randomXWrmsr,omitempty"` + // RandomXNoRdmsr enables or disables MSR reading for RandomX. + RandomXNoRdmsr bool `json:"randomXNoRdmsr,omitempty"` + // RandomXCacheQoS enables or disables QoS for the RandomX cache. + RandomXCacheQoS bool `json:"randomXCacheQoS,omitempty"` // API options (can be overridden or supplemented here) - APIWorkerID string `json:"apiWorkerId,omitempty"` - APIID string `json:"apiId,omitempty"` - HTTPHost string `json:"httpHost,omitempty"` - HTTPPort int `json:"httpPort,omitempty"` - HTTPAccessToken string `json:"httpAccessToken,omitempty"` - HTTPNoRestricted bool `json:"httpNoRestricted,omitempty"` + // APIWorkerID is the worker ID for the API. + APIWorkerID string `json:"apiWorkerId,omitempty"` + // APIID is the ID for the API. + APIID string `json:"apiId,omitempty"` + // HTTPHost is the host for the HTTP API. + HTTPHost string `json:"httpHost,omitempty"` + // HTTPPort is the port for the HTTP API. + HTTPPort int `json:"httpPort,omitempty"` + // HTTPAccessToken is the access token for the HTTP API. + HTTPAccessToken string `json:"httpAccessToken,omitempty"` + // HTTPNoRestricted enables or disables restricted access to the HTTP API. + HTTPNoRestricted bool `json:"httpNoRestricted,omitempty"` // Logging options - Syslog bool `json:"syslog,omitempty"` - LogFile string `json:"logFile,omitempty"` - PrintTime int `json:"printTime,omitempty"` - HealthPrintTime int `json:"healthPrintTime,omitempty"` - NoColor bool `json:"noColor,omitempty"` - Verbose bool `json:"verbose,omitempty"` - LogOutput bool `json:"logOutput,omitempty"` // New field to control stdout/stderr logging + // Syslog enables or disables logging to the system log. + Syslog bool `json:"syslog,omitempty"` + // LogFile is the path to the log file. + LogFile string `json:"logFile,omitempty"` + // PrintTime is the interval in seconds for printing performance metrics. + PrintTime int `json:"printTime,omitempty"` + // HealthPrintTime is the interval in seconds for printing health metrics. + HealthPrintTime int `json:"healthPrintTime,omitempty"` + // NoColor disables color output in the logs. + NoColor bool `json:"noColor,omitempty"` + // Verbose enables verbose logging. + Verbose bool `json:"verbose,omitempty"` + // LogOutput enables or disables logging of stdout/stderr. + LogOutput bool `json:"logOutput,omitempty"` // Misc options - Background bool `json:"background,omitempty"` - Title string `json:"title,omitempty"` - NoTitle bool `json:"noTitle,omitempty"` - PauseOnBattery bool `json:"pauseOnBattery,omitempty"` - PauseOnActive int `json:"pauseOnActive,omitempty"` - Stress bool `json:"stress,omitempty"` - Bench string `json:"bench,omitempty"` - Submit bool `json:"submit,omitempty"` - Verify string `json:"verify,omitempty"` - Seed string `json:"seed,omitempty"` - Hash string `json:"hash,omitempty"` - NoDMI bool `json:"noDMI,omitempty"` + // Background runs the miner in the background. + Background bool `json:"background,omitempty"` + // Title sets the title of the miner window. + Title string `json:"title,omitempty"` + // NoTitle disables the miner window title. + NoTitle bool `json:"noTitle,omitempty"` + // PauseOnBattery pauses the miner when the system is on battery power. + PauseOnBattery bool `json:"pauseOnBattery,omitempty"` + // PauseOnActive pauses the miner when the user is active. + PauseOnActive int `json:"pauseOnActive,omitempty"` + // Stress enables stress testing mode. + Stress bool `json:"stress,omitempty"` + // Bench enables benchmark mode. + Bench string `json:"bench,omitempty"` + // Submit enables or disables submitting shares. + Submit bool `json:"submit,omitempty"` + // Verify enables or disables share verification. + Verify string `json:"verify,omitempty"` + // Seed is the seed for the random number generator. + Seed string `json:"seed,omitempty"` + // Hash is the hash for the random number generator. + Hash string `json:"hash,omitempty"` + // NoDMI disables DMI/SMBIOS probing. + NoDMI bool `json:"noDMI,omitempty"` } -// PerformanceMetrics represents the performance metrics for a miner +// PerformanceMetrics represents the performance metrics for a miner. +// This struct provides a standardized way to report key performance indicators +// such as hashrate, shares, and uptime, allowing for consistent monitoring +// and comparison across different miners. type PerformanceMetrics struct { - Hashrate int `json:"hashrate"` - Shares int `json:"shares"` - Rejected int `json:"rejected"` - Uptime int `json:"uptime"` - LastShare int64 `json:"lastShare"` - Algorithm string `json:"algorithm"` + // Hashrate is the current hashrate of the miner in H/s. + Hashrate int `json:"hashrate"` + // Shares is the number of shares submitted by the miner. + Shares int `json:"shares"` + // Rejected is the number of rejected shares. + Rejected int `json:"rejected"` + // Uptime is the duration the miner has been running, in seconds. + Uptime int `json:"uptime"` + // LastShare is the timestamp of the last submitted share. + LastShare int64 `json:"lastShare"` + // Algorithm is the mining algorithm currently in use. + Algorithm string `json:"algorithm"` + // ExtraData provides a flexible way to include additional, miner-specific + // performance data that is not covered by the standard fields. ExtraData map[string]interface{} `json:"extraData,omitempty"` } -// History represents the history of a miner +// History represents the historical performance data for a miner. +// It contains a collection of performance metrics snapshots, allowing for +// the tracking of a miner's performance over time. type History struct { - Miner string `json:"miner"` - Stats []PerformanceMetrics `json:"stats"` - Updated int64 `json:"updated"` + // Miner is the name of the miner. + Miner string `json:"miner"` + // Stats is a slice of performance metrics, representing the historical data. + Stats []PerformanceMetrics `json:"stats"` + // Updated is the timestamp of the last update to the history. + Updated int64 `json:"updated"` } -// HashratePoint represents a single hashrate measurement at a specific time +// HashratePoint represents a single hashrate measurement at a specific time. +// This struct is used to build a time-series history of a miner's hashrate, +// which is essential for performance analysis and visualization. type HashratePoint struct { + // Timestamp is the time at which the hashrate was measured. Timestamp time.Time `json:"timestamp"` - Hashrate int `json:"hashrate"` + // Hashrate is the measured hashrate in H/s. + Hashrate int `json:"hashrate"` } -// XMRigMiner represents an XMRig miner +// XMRigMiner represents an XMRig miner, encapsulating its configuration, +// state, and operational details. This struct provides a comprehensive +// representation of an XMRig miner instance, including its identity, +// connection details, and performance history. type XMRigMiner struct { - Name string `json:"name"` - Version string `json:"version"` - URL string `json:"url"` - Path string `json:"path"` // This will now be the versioned folder path - MinerBinary string `json:"miner_binary"` // New field for the full path to the miner executable - Running bool `json:"running"` - LastHeartbeat int64 `json:"lastHeartbeat"` - ConfigPath string `json:"configPath"` - API *API `json:"api"` - mu sync.Mutex - cmd *exec.Cmd `json:"-"` - HashrateHistory []HashratePoint `json:"hashrateHistory"` // High-resolution (10s) - LowResHashrateHistory []HashratePoint `json:"lowResHashrateHistory"` // Low-resolution (1m averages) - LastLowResAggregation time.Time `json:"-"` // Timestamp of the last low-res aggregation + // Name is the name of the miner. + Name string `json:"name"` + // Version is the version of the XMRig miner. + Version string `json:"version"` + // URL is the download URL for the XMRig miner. + URL string `json:"url"` + // Path is the installation path of the miner. + Path string `json:"path"` + // MinerBinary is the full path to the miner's executable file. + MinerBinary string `json:"miner_binary"` + // Running indicates whether the miner is currently running. + Running bool `json:"running"` + // LastHeartbeat is the timestamp of the last heartbeat from the miner. + LastHeartbeat int64 `json:"lastHeartbeat"` + // ConfigPath is the path to the miner's configuration file. + ConfigPath string `json:"configPath"` + // API provides access to the miner's API for statistics and control. + API *API `json:"api"` + // mu is a mutex to protect against concurrent access to the miner's state. + mu sync.Mutex + // cmd is the command used to execute the miner process. + cmd *exec.Cmd `json:"-"` + // HashrateHistory is a slice of high-resolution hashrate data points. + HashrateHistory []HashratePoint `json:"hashrateHistory"` + // LowResHashrateHistory is a slice of low-resolution hashrate data points. + LowResHashrateHistory []HashratePoint `json:"lowResHashrateHistory"` + // LastLowResAggregation is the timestamp of the last low-resolution aggregation. + LastLowResAggregation time.Time `json:"-"` } -// API represents the XMRig API configuration +// API represents the XMRig API configuration. +// It specifies the details needed to connect to the miner's API, +// enabling programmatic monitoring and control. type API struct { - Enabled bool `json:"enabled"` + // Enabled indicates whether the API is enabled. + Enabled bool `json:"enabled"` + // ListenHost is the host on which the API is listening. ListenHost string `json:"listenHost"` - ListenPort int `json:"listenPort"` + // ListenPort is the port on which the API is listening. + ListenPort int `json:"listenPort"` } -// XMRigSummary represents the summary from the XMRig API +// XMRigSummary represents the summary of an XMRig miner's performance, +// as retrieved from its API. This struct provides a structured way to +// access key performance indicators from the miner's API. type XMRigSummary struct { + // Hashrate contains the hashrate data from the API. Hashrate struct { Total []float64 `json:"total"` } `json:"hashrate"` + // Results contains the share statistics from the API. Results struct { SharesGood uint64 `json:"shares_good"` SharesTotal uint64 `json:"shares_total"` } `json:"results"` - Uptime uint64 `json:"uptime"` + // Uptime is the duration the miner has been running, in seconds. + Uptime uint64 `json:"uptime"` + // Algorithm is the mining algorithm currently in use. Algorithm string `json:"algorithm"` } -// AvailableMiner represents a miner that is available to be started +// AvailableMiner represents a miner that is available for use. +// It provides a simple way to list and describe the miners that can be +// started and managed by the system. type AvailableMiner struct { - Name string `json:"name"` + // Name is the name of the available miner. + Name string `json:"name"` + // Description is a brief description of the miner. Description string `json:"description"` } diff --git a/pkg/mining/xmrig.go b/pkg/mining/xmrig.go index 9a524c6..d9763a5 100644 --- a/pkg/mining/xmrig.go +++ b/pkg/mining/xmrig.go @@ -26,10 +26,20 @@ var httpClient = &http.Client{ Timeout: 30 * time.Second, } -// NewXMRigMiner creates a new XMRig miner +// NewXMRigMiner creates a new XMRig miner instance with default settings. +// This is the entry point for creating a new XMRig miner that can be managed +// by the Manager. The returned miner is ready to be installed and started. +// +// Example: +// +// // Create a new XMRig miner +// xmrigMiner := mining.NewXMRigMiner() +// +// // Now you can use the miner to perform actions like +// // installing, starting, and stopping. func NewXMRigMiner() *XMRigMiner { return &XMRigMiner{ - Name: "xmrig", // Changed to lowercase for consistency + Name: "xmrig", Version: "latest", URL: "https://github.com/xmrig/xmrig/releases", API: &API{ @@ -43,28 +53,30 @@ func NewXMRigMiner() *XMRigMiner { } } -// GetName returns the name of the miner +// GetName returns the name of the miner. func (m *XMRigMiner) GetName() string { return m.Name } -// GetPath returns the path of the miner -// This now returns the base installation directory for xmrig, not the versioned one. +// GetPath returns the base installation directory for the XMRig miner. +// This is the directory where different versions of the miner are stored. func (m *XMRigMiner) GetPath() string { dataPath, err := xdg.DataFile("lethean-desktop/miners/xmrig") if err != nil { - // Fallback for safety, though it should ideally not fail if Install works. return "" } return dataPath } -// GetBinaryPath returns the full path to the miner executable. +// GetBinaryPath returns the full path to the miner's executable file. +// This path is set after a successful installation or check of the installation status. func (m *XMRigMiner) GetBinaryPath() string { return m.MinerBinary } -// GetLatestVersion returns the latest version of XMRig +// GetLatestVersion fetches the latest version of XMRig from the GitHub API. +// It returns the version string (e.g., "v6.18.0") or an error if the +// version could not be retrieved. func (m *XMRigMiner) GetLatestVersion() (string, error) { resp, err := httpClient.Get("https://api.github.com/repos/xmrig/xmrig/releases/latest") if err != nil { @@ -85,7 +97,9 @@ func (m *XMRigMiner) GetLatestVersion() (string, error) { return release.TagName, nil } -// Download and install the latest version of XMRig +// Install downloads and installs the latest version of the XMRig miner. +// It determines the correct release for the current operating system, +// downloads it, and extracts it to the appropriate installation directory. func (m *XMRigMiner) Install() error { version, err := m.GetLatestVersion() if err != nil { @@ -156,14 +170,17 @@ func (m *XMRigMiner) Install() error { return nil } -// Uninstall removes the miner files +// Uninstall removes all files related to the XMRig miner. +// This is a destructive operation that will remove the entire installation +// directory of the miner. func (m *XMRigMiner) Uninstall() error { - // Uninstall should remove the base path, which contains the versioned folder return os.RemoveAll(m.GetPath()) } -// findMinerBinary searches for the miner executable, first in the standard installation path, -// then falls back to the system's PATH. +// findMinerBinary searches for the miner's executable file. +// It first checks the standard installation path, and if not found, falls +// back to searching the system's PATH. This allows for both managed +// installations and pre-existing installations to be used. func (m *XMRigMiner) findMinerBinary() (string, error) { executableName := "xmrig" if runtime.GOOS == "windows" { @@ -198,7 +215,10 @@ func (m *XMRigMiner) findMinerBinary() (string, error) { return "", errors.New("miner executable not found in standard directory or system PATH") } -// CheckInstallation checks if the miner is installed and returns its details +// CheckInstallation verifies if the XMRig miner is installed correctly. +// It returns details about the installation, such as whether it is installed, +// its version, and the path to the executable. This method also updates the +// miner's internal state with the installation details. func (m *XMRigMiner) CheckInstallation() (*InstallationDetails, error) { details := &InstallationDetails{} @@ -236,7 +256,28 @@ func (m *XMRigMiner) CheckInstallation() (*InstallationDetails, error) { return details, nil } -// Start the miner +// Start launches the XMRig miner with the specified configuration. +// It creates a configuration file, constructs the necessary command-line +// arguments, and starts the miner process in the background. +// +// Example: +// +// // Create a new XMRig miner and a configuration +// xmrigMiner := mining.NewXMRigMiner() +// config := &mining.Config{ +// Pool: "your-pool-address", +// Wallet: "your-wallet-address", +// Threads: 4, +// } +// +// // Start the miner +// err := xmrigMiner.Start(config) +// if err != nil { +// log.Fatalf("Failed to start miner: %v", err) +// } +// +// // Stop the miner when you are done +// defer xmrigMiner.Stop() func (m *XMRigMiner) Start(config *Config) error { m.mu.Lock() defer m.mu.Unlock() @@ -500,7 +541,8 @@ func (m *XMRigMiner) Start(config *Config) error { return nil } -// Stop the miner +// Stop terminates the XMRig miner process. +// It sends a kill signal to the running miner process. func (m *XMRigMiner) Stop() error { m.mu.Lock() defer m.mu.Unlock() @@ -512,7 +554,9 @@ func (m *XMRigMiner) Stop() error { return m.cmd.Process.Kill() } -// GetStats returns the stats for the miner +// GetStats retrieves the performance statistics from the running XMRig miner. +// It queries the miner's API and returns a PerformanceMetrics struct +// containing the hashrate, share counts, and uptime. func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) { m.mu.Lock() running := m.Running @@ -552,6 +596,7 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) { } // GetHashrateHistory returns the combined high-resolution and low-resolution hashrate history. +// This provides a complete view of the miner's performance over time. func (m *XMRigMiner) GetHashrateHistory() []HashratePoint { m.mu.Lock() defer m.mu.Unlock() @@ -565,73 +610,69 @@ func (m *XMRigMiner) GetHashrateHistory() []HashratePoint { } // AddHashratePoint adds a new hashrate measurement to the high-resolution history. +// This method is called periodically by the Manager to record the miner's performance. func (m *XMRigMiner) AddHashratePoint(point HashratePoint) { m.mu.Lock() defer m.mu.Unlock() m.HashrateHistory = append(m.HashrateHistory, point) - // No trimming here; trimming is handled by ReduceHashrateHistory } -// ReduceHashrateHistory aggregates older high-resolution data into 1-minute averages -// and adds them to the low-resolution history. +// GetHighResHistoryLength returns the number of data points in the high-resolution hashrate history. func (m *XMRigMiner) GetHighResHistoryLength() int { m.mu.Lock() defer m.mu.Unlock() return len(m.HashrateHistory) } +// GetLowResHistoryLength returns the number of data points in the low-resolution hashrate history. func (m *XMRigMiner) GetLowResHistoryLength() int { m.mu.Lock() defer m.mu.Unlock() return len(m.LowResHashrateHistory) } +// ReduceHashrateHistory aggregates older high-resolution hashrate data into +// lower-resolution data, and trims the history to a manageable size. +// This method is called periodically by the Manager to maintain the hashrate +// history. func (m *XMRigMiner) ReduceHashrateHistory(now time.Time) { m.mu.Lock() defer m.mu.Unlock() // Only aggregate if enough time has passed since the last aggregation - // or if it's the first aggregation if !m.LastLowResAggregation.IsZero() && now.Sub(m.LastLowResAggregation) < LowResolutionInterval { return } - // Find points in HashrateHistory that are older than HighResolutionDuration - // These are the candidates for aggregation into low-resolution history. var pointsToAggregate []HashratePoint var newHighResHistory []HashratePoint // The cutoff is exclusive: points *at or before* this time are candidates for aggregation. // We want to aggregate points that are *strictly older* than HighResolutionDuration ago. - // So, if HighResolutionDuration is 5 minutes, points older than (now - 5 minutes) are aggregated. cutoff := now.Add(-HighResolutionDuration) for _, p := range m.HashrateHistory { - if p.Timestamp.Before(cutoff) { // Use Before to ensure strict older-than + if p.Timestamp.Before(cutoff) { pointsToAggregate = append(pointsToAggregate, p) } else { newHighResHistory = append(newHighResHistory, p) } } - m.HashrateHistory = newHighResHistory // Update high-res history to only contain recent points + m.HashrateHistory = newHighResHistory if len(pointsToAggregate) == 0 { - // If no points to aggregate, just update LastLowResAggregation and return m.LastLowResAggregation = now return } - // Aggregate into 1-minute slices - // Group points by minute (truncated timestamp) + // Group points by minute and calculate average hashrate minuteGroups := make(map[time.Time][]int) for _, p := range pointsToAggregate { - // Round timestamp down to the nearest minute for grouping minute := p.Timestamp.Truncate(LowResolutionInterval) minuteGroups[minute] = append(minuteGroups[minute], p.Hashrate) } - // Calculate average for each minute and add to low-res history var newLowResPoints []HashratePoint for minute, hashrates := range minuteGroups { if len(hashrates) > 0 { @@ -647,7 +688,6 @@ func (m *XMRigMiner) ReduceHashrateHistory(now time.Time) { } } - // Sort new low-res points by timestamp to maintain chronological order sort.Slice(newLowResPoints, func(i, j int) bool { return newLowResPoints[i].Timestamp.Before(newLowResPoints[j].Timestamp) }) @@ -656,15 +696,14 @@ func (m *XMRigMiner) ReduceHashrateHistory(now time.Time) { // Trim low-resolution history to LowResHistoryRetention lowResCutoff := now.Add(-LowResHistoryRetention) - // Find the first point that is *after* or equal to the lowResCutoff firstValidLowResIndex := 0 for i, p := range m.LowResHashrateHistory { if p.Timestamp.After(lowResCutoff) || p.Timestamp.Equal(lowResCutoff) { firstValidLowResIndex = i break } - if i == len(m.LowResHashrateHistory)-1 { // All points are older than cutoff - firstValidLowResIndex = len(m.LowResHashrateHistory) // Clear all + if i == len(m.LowResHashrateHistory)-1 { + firstValidLowResIndex = len(m.LowResHashrateHistory) } } m.LowResHashrateHistory = m.LowResHashrateHistory[firstValidLowResIndex:] @@ -672,6 +711,9 @@ func (m *XMRigMiner) ReduceHashrateHistory(now time.Time) { m.LastLowResAggregation = now } +// createConfig creates a JSON configuration file for the XMRig miner. +// This allows for a consistent and reproducible way to configure the miner, +// based on the provided Config struct. func (m *XMRigMiner) createConfig(config *Config) error { configPath, err := xdg.ConfigFile("lethean-desktop/xmrig.json") if err != nil { @@ -717,6 +759,8 @@ func (m *XMRigMiner) createConfig(config *Config) error { return os.WriteFile(m.ConfigPath, data, 0644) } +// unzip extracts a zip archive to a destination directory. +// This is a helper function used during the installation of the miner. func (m *XMRigMiner) unzip(src, dest string) error { r, err := zip.OpenReader(src) if err != nil { @@ -762,6 +806,8 @@ func (m *XMRigMiner) unzip(src, dest string) error { return nil } +// untar extracts a tar.gz archive to a destination directory. +// This is a helper function used during the installation of the miner. func (m *XMRigMiner) untar(src, dest string) error { file, err := os.Open(src) if err != nil {