354 lines
8.8 KiB
Go
354 lines
8.8 KiB
Go
/*
|
||
持续挖矿
|
||
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
|
||
}
|