Files
mining-client/internal/sustain/proxy.go
2025-12-01 15:45:05 +08:00

354 lines
8.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
持续挖矿
1在主配置文件中选择是否开启
2开启后将读取挖矿配置(mining.conf)
3根据配置启动相应的挖矿软件开始挖矿
4接收到tcp协议传送过来的新挖矿任务后停止当前挖矿并开启新的挖矿
5新挖矿任务到期或结束后重新开启挖矿
配置文件:算法、挖矿软件、挖矿配置(算法、钱包、矿工号、挖矿地址)
*/
package sustain
import (
message "client/internal/msg"
"client/internal/src"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
"gopkg.in/ini.v1"
)
// SustainMiningConfig 持续挖矿配置
type SustainMiningConfig struct {
Enabled bool // 是否启用持续挖矿
Algo string // 算法
Coin string // 币种
Miner string // 挖矿软件 (lolminer/bzminer/rigel)
PoolUrl string // 矿池地址
Wallet string // 钱包地址
WorkerID string // 矿工号
PoolUser string // 矿池账号(可选)
WalletMining bool // 是否使用钱包挖矿
}
// SustainMiner 持续挖矿管理器
type SustainMiner struct {
mu sync.Mutex
config SustainMiningConfig
miningConfig message.MiningConfig
os *src.SystemServer
osName string
currentProcess *exec.Cmd // 当前挖矿进程
isRunning bool // 是否正在运行持续挖矿
isPaused bool // 是否被暂停(因为有新任务)
stopChan chan struct{} // 停止信号
}
// NewSustainMiner 创建持续挖矿管理器
func NewSustainMiner(os *src.SystemServer, osName string, miningConfig message.MiningConfig) *SustainMiner {
return &SustainMiner{
os: os,
osName: osName,
miningConfig: miningConfig,
stopChan: make(chan struct{}),
}
}
// LoadConfig 从配置文件加载持续挖矿配置
func (s *SustainMiner) LoadConfig() error {
var confFile string
if runtime.GOOS == "windows" {
confFile = "mining.windows.conf"
} else {
confFile = "mining.linux.conf"
}
cfg, err := ini.Load(confFile)
if err != nil {
return fmt.Errorf("读取配置文件失败: %v", err)
}
// 读取 [sustain] 部分
section := cfg.Section("sustain")
s.config.Enabled, _ = section.Key("enabled").Bool()
if !s.config.Enabled {
log.Println("持续挖矿未启用")
return nil
}
// 读取配置值,并去掉可能的引号
s.config.Algo = strings.Trim(section.Key("algo").String(), `"`)
s.config.Coin = strings.Trim(section.Key("coin").String(), `"`)
s.config.Miner = strings.Trim(section.Key("miner").String(), `"`)
s.config.PoolUrl = strings.Trim(section.Key("pool_url").String(), `"`)
s.config.Wallet = strings.Trim(section.Key("wallet").String(), `"`)
s.config.WorkerID = strings.Trim(section.Key("worker_id").String(), `"`)
s.config.PoolUser = strings.Trim(section.Key("pool_user").String(), `"`)
s.config.WalletMining, _ = section.Key("wallet_mining").Bool()
// 验证配置
if s.config.Algo == "" || s.config.Coin == "" || s.config.Miner == "" ||
s.config.PoolUrl == "" || s.config.Wallet == "" || s.config.WorkerID == "" {
return fmt.Errorf("持续挖矿配置不完整")
}
// 验证挖矿软件路径
switch strings.ToLower(s.config.Miner) {
case "lolminer":
if s.miningConfig.LolMinerPath == "" {
return fmt.Errorf("lolminer 路径未配置")
}
case "bzminer":
if s.miningConfig.BzMinerPath == "" {
return fmt.Errorf("bzminer 路径未配置")
}
case "rigel":
if s.miningConfig.RigelPath == "" {
return fmt.Errorf("rigel 路径未配置")
}
default:
return fmt.Errorf("不支持的挖矿软件: %s", s.config.Miner)
}
log.Printf("持续挖矿配置加载成功: 算法=%s, 币种=%s, 挖矿软件=%s", s.config.Algo, s.config.Coin, s.config.Miner)
return nil
}
// Start 启动持续挖矿
func (s *SustainMiner) Start() error {
s.mu.Lock()
defer s.mu.Unlock()
if !s.config.Enabled {
return nil
}
if s.isRunning {
log.Println("持续挖矿已在运行中")
return nil
}
s.isRunning = true
s.isPaused = false
s.stopChan = make(chan struct{})
log.Println("启动持续挖矿...")
go s.run()
return nil
}
// Stop 停止持续挖矿
func (s *SustainMiner) Stop() {
s.mu.Lock()
defer s.mu.Unlock()
if !s.isRunning {
return
}
log.Println("停止持续挖矿...")
close(s.stopChan)
s.isRunning = false
// 停止当前挖矿进程
if s.currentProcess != nil && s.currentProcess.Process != nil {
log.Println("停止当前挖矿进程...")
if runtime.GOOS == "linux" && s.config.Miner == "rigel" {
// Linux rigel 使用 Interrupt 信号
s.currentProcess.Process.Signal(os.Interrupt)
} else {
s.currentProcess.Process.Kill()
}
s.currentProcess = nil
}
}
// Pause 暂停持续挖矿(当有新任务时调用)
func (s *SustainMiner) Pause() {
s.mu.Lock()
defer s.mu.Unlock()
if !s.isRunning || s.isPaused {
return
}
log.Println("暂停持续挖矿(有新任务)...")
s.isPaused = true
// 停止当前挖矿进程
if s.currentProcess != nil && s.currentProcess.Process != nil {
if runtime.GOOS == "linux" && s.config.Miner == "rigel" {
s.currentProcess.Process.Signal(os.Interrupt)
} else {
s.currentProcess.Process.Kill()
}
s.currentProcess = nil
}
}
// Resume 恢复持续挖矿(当任务结束后调用)
func (s *SustainMiner) Resume() {
s.mu.Lock()
defer s.mu.Unlock()
if !s.isRunning || !s.isPaused {
return
}
log.Println("恢复持续挖矿...")
s.isPaused = false
// 重新启动挖矿
go s.startMining()
}
// run 持续挖矿主循环
func (s *SustainMiner) run() {
for {
select {
case <-s.stopChan:
log.Println("持续挖矿已停止")
return
default:
s.mu.Lock()
paused := s.isPaused
s.mu.Unlock()
if !paused {
s.startMining()
// 等待挖矿进程结束(正常情况下不会结束,除非被停止)
if s.currentProcess != nil {
s.currentProcess.Wait()
}
} else {
// 如果被暂停,等待恢复
time.Sleep(1 * time.Second)
}
}
}
}
// startMining 启动挖矿进程
func (s *SustainMiner) startMining() {
s.mu.Lock()
defer s.mu.Unlock()
if s.isPaused {
return
}
var cmd *exec.Cmd
var err error
address := s.config.Wallet
if !s.config.WalletMining && s.config.PoolUser != "" {
address = s.config.PoolUser
}
switch strings.ToLower(s.config.Miner) {
case "lolminer":
cmd, err = s.startLolMiner(address)
case "bzminer":
cmd, err = s.startBzMiner(address)
case "rigel":
cmd, err = s.startRigel(address)
default:
log.Printf("不支持的挖矿软件: %s", s.config.Miner)
return
}
if err != nil {
log.Printf("启动持续挖矿失败: %v", err)
return
}
s.currentProcess = cmd
log.Printf("持续挖矿已启动: %s (PID: %d)", s.config.Miner, cmd.Process.Pid)
}
// startLolMiner 启动 lolminer
func (s *SustainMiner) startLolMiner(address string) (*exec.Cmd, error) {
dir := s.miningConfig.LolMinerPath
var name string
if runtime.GOOS == "windows" {
name = filepath.Join(dir, "lolMiner.exe")
} else {
name = filepath.Join(dir, "lolMiner")
}
args := []string{"--algo", s.config.Coin, "--pool", s.config.PoolUrl, "--user", address + "." + s.config.WorkerID}
cmd := exec.Command(name, args...)
cmd.Dir = dir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("启动持续挖矿 lolminer: %s %s", name, strings.Join(args, " "))
err := cmd.Start()
return cmd, err
}
// startBzMiner 启动 bzminer
func (s *SustainMiner) startBzMiner(address string) (*exec.Cmd, error) {
dir := s.miningConfig.BzMinerPath
var name string
if runtime.GOOS == "windows" {
name = filepath.Join(dir, "bzminer.exe")
} else {
name = filepath.Join(dir, "bzminer")
}
args := []string{"-a", s.config.Coin, "-w", address + "." + s.config.WorkerID, "-p", s.config.PoolUrl}
cmd := exec.Command(name, args...)
cmd.Dir = dir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("启动持续挖矿 bzminer: %s %s", name, strings.Join(args, " "))
err := cmd.Start()
return cmd, err
}
// startRigel 启动 rigel
func (s *SustainMiner) startRigel(address string) (*exec.Cmd, error) {
dir := s.miningConfig.RigelPath
var name string
if runtime.GOOS == "windows" {
name = filepath.Join(dir, "rigel.exe")
} else {
name = filepath.Join(dir, "rigel")
}
args := []string{"--no-watchdog", "-a", strings.ToLower(s.config.Algo), "-o", s.config.PoolUrl, "-u", address, "-w", s.config.WorkerID, "--log-file", "logs/miner.log"}
cmd := exec.Command(name, args...)
cmd.Dir = dir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("启动持续挖矿 rigel: %s %s", name, strings.Join(args, " "))
err := cmd.Start()
return cmd, err
}
// IsRunning 检查是否正在运行
func (s *SustainMiner) IsRunning() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.isRunning && !s.isPaused
}
// IsPaused 检查是否被暂停
func (s *SustainMiner) IsPaused() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.isPaused
}