diff --git a/bin/client_linux b/bin/client_linux new file mode 100644 index 0000000..2fa8fd6 Binary files /dev/null and b/bin/client_linux differ diff --git a/bin/mining_task.db b/bin/mining_task.db new file mode 100644 index 0000000..9784f3b Binary files /dev/null and b/bin/mining_task.db differ diff --git a/bin/用户手册.txt b/bin/用户手册.txt index 09948bb..b220777 100644 --- a/bin/用户手册.txt +++ b/bin/用户手册.txt @@ -5,7 +5,7 @@ 1,请您根据您的GPU所在主机的操作系统,下载正确系统版本的客户端,windows或linux(ubuntu等) 2,必须通过官网且在正确的卖家账号下下载本客户端,因为里面包含您的卖家信息,如果通过非官方渠道或错误的卖家账号下载了客户端,您的GPU信息无法同步到云算力平台 3,下载并解压后,请确定您的客户端包含以下文件: - 执行文件(client.exe或client) + 执行文件(client_windows.exe或client_linux) auth mining.linux.conf mining.windows.conf diff --git a/cmd/build.windows.bat b/cmd/build.windows.bat index 16065c4..11c23a0 100644 --- a/cmd/build.windows.bat +++ b/cmd/build.windows.bat @@ -1,8 +1,13 @@ @echo off + +:: 设置目标平台为 Windows 和 amd64(64位) +set GOOS=windows +set GOARCH=amd64 + cd /d %~dp0 -go build -o ../bin/client.exe main.go +go build -o ../bin/client_windows.exe main.go if %errorlevel% equ 0 ( - echo 编译成功!可执行文件位于: ..\bin\client.exe + echo 编译成功!可执行文件位于: ..\bin\client_windows.exe ) else ( echo 编译失败! exit /b %errorlevel% diff --git a/cmd/build.windows_linux.bat b/cmd/build.windows_linux.bat new file mode 100644 index 0000000..e248465 --- /dev/null +++ b/cmd/build.windows_linux.bat @@ -0,0 +1,28 @@ +@echo off +setlocal + +:: 设置目标平台为 Linux 和 amd64 +set GOOS=linux +set GOARCH=amd64 + +:: 可选:设置编译输出目录 +set OUTPUT_DIR=../bin + +:: 确保输出目录存在 +if not exist %OUTPUT_DIR% ( + mkdir %OUTPUT_DIR% +) + +:: 编译 Go 程序 +go build -o %OUTPUT_DIR%/client_linux main.go + +:: 检查编译结果 +if %ERRORLEVEL% NEQ 0 ( + echo 编译失败! + exit /b %ERRORLEVEL% +) + +echo 编译成功!可执行文件位于 %OUTPUT_DIR%/client_linux + +endlocal +pause \ No newline at end of file diff --git a/internal/client.go b/internal/client.go index 45103cd..42dd898 100644 --- a/internal/client.go +++ b/internal/client.go @@ -14,6 +14,7 @@ package client import ( + "bufio" message "client/internal/msg" "client/internal/src" "client/internal/src/linux" @@ -39,6 +40,7 @@ type Client struct { MachineCode string ServerConn net.Conn // 服务连接 GPUs map[int]message.GPU // {"gpu编号": message.GPU{}, ...} + MiningSofts []string os *src.SystemServer osName string serverURL string // 服务器地址 @@ -58,7 +60,7 @@ func newClient(url string) *Client { // 读取身份文件 auth, err := utils.ReadFile("./auth") if err != nil { - log.Fatalf("获取客户端身份失败:%v", err) + log.Printf("获取客户端身份失败:%v", err) return nil } @@ -101,31 +103,32 @@ func newClient(url string) *Client { } else { confFile = "mining.linux.conf" } - + var softs = make([]string, 0) // 读取挖矿配置 cfg, err := ini.Load(confFile) if err == nil { - sectionBzMiner := cfg.Section("bzminer") - miningConfig.BzMinerPath = sectionBzMiner.Key("path").String() - sectionLolMiner := cfg.Section("lolminer") miningConfig.LolMinerPath = sectionLolMiner.Key("path").String() - + if miningConfig.LolMinerPath != "" { + softs = append(softs, "lolminer") + } sectionRigel := cfg.Section("rigel") miningConfig.RigelPath = sectionRigel.Key("path").String() - + if miningConfig.RigelPath != "" { + softs = append(softs, "rigel") + } sectionProxy := cfg.Section("proxy") miningConfig.ProxyEnabled, _ = sectionProxy.Key("proxy").Bool() } - + client.MiningSofts = softs client.sustainMiner = sustain.NewSustainMiner(systemServer, sys, miningConfig) // 读取主机MAC地址信息 var machine_code string machine_code, err = systemServer.GetMACAddress(sys) if err != nil { - log.Fatalln(err) - panic("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") + log.Println(err) + log.Fatalln("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") } // utils.WirteFile("./machinecode", machine_code) @@ -133,8 +136,8 @@ func newClient(url string) *Client { gpus, err := systemServer.GetGPUInfo(sys) if err != nil { - log.Fatalln(err) - panic("获取当前主机GPU数据失败,程序已退出,请检查GPU驱动等程序后重新启动本客户端。") + log.Println(err) + log.Fatalln("获取当前主机GPU数据失败,程序已退出,请检查GPU驱动等程序后重新启动本客户端。") } client.GPUs = gpus client.serverURL = url @@ -144,7 +147,7 @@ func newClient(url string) *Client { // 连接服务端 server_conn, err := net.Dial("tcp", url) if err != nil { - log.Fatalf("客户端连接到服务器失败:%v", err) + log.Printf("客户端连接到服务器失败:%v", err) return nil } @@ -171,14 +174,18 @@ func (c *Client) Stop() { func (c *Client) sendMachineCode() { var msg message.ServerMsg - msg.ID = c.Auth + "." + c.MachineCode + msg.ID = c.Auth + "::" + c.MachineCode msg.Method = "auth.machineCode" - msg.Params = c.GPUs + var params = make(map[string]any) + params["gpus"] = c.GPUs + params["miningsofts"] = c.MiningSofts + msg.Params = params msgByte, err := json.Marshal(msg) if err != nil { - log.Fatalf("消息(%v)序列化失败:%v", msg, err) + log.Printf("消息(%v)序列化失败:%v", msg, err) return } + log.Println(string(msgByte)) c.send(msgByte) } @@ -192,7 +199,8 @@ func (c *Client) receiveMsg() { c.mu.Unlock() }() - buffer := make([]byte, 1024) + // 使用 bufio.Reader 读取数据 + reader := bufio.NewReader(c.ServerConn) for { c.mu.Lock() @@ -206,26 +214,29 @@ func (c *Client) receiveMsg() { // 设置读取超时,用于检测连接是否存活 conn.SetReadDeadline(time.Now().Add(60 * time.Second)) - n, err := conn.Read(buffer) + + // 读取一行数据,直到遇到换行符 + msgByte, err := reader.ReadString('\n') if err != nil { - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - log.Println("读取超时,连接可能已断开") - c.reconnect() - return - } if err.Error() == "EOF" { // 服务端关闭连接时,退出接收循环 log.Println("服务端关闭了连接") c.reconnect() return } + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + log.Println("读取超时,连接可能已断开") + c.reconnect() + return + } log.Printf("接收数据失败: %v", err) c.reconnect() return } - msgByte := buffer[:n] - go c.handleReceiveMsg(msgByte) + // 输出接收到的消息 + log.Printf("收到新消息:%s", msgByte) + go c.handleReceiveMsg([]byte(msgByte)) // 处理消息 } } @@ -237,7 +248,7 @@ func (c *Client) send(msg []byte) error { return fmt.Errorf("连接已断开") } - _, err := c.ServerConn.Write(msg) + _, err := c.ServerConn.Write(append(msg, '\n')) if err != nil { log.Printf("发送消息失败:%v\n消息内容:%s", err, string(msg)) return err @@ -249,26 +260,43 @@ func (c *Client) handleReceiveMsg(msg []byte) { var data message.ServerMsg err := json.Unmarshal(msg, &data) if err != nil { - log.Fatalf("解析接收到的消息失败:%v", err) + log.Printf("解析接收到的消息失败:%v", err) return } - parts := strings.Split(data.ID, ".") + parts := strings.Split(data.ID, "::") if len(parts) != 2 { - log.Fatalf("解析通信协议(server->client)失败") + log.Printf("解析通信协议(server->client)失败") return } auth, machine_code := parts[0], parts[1] if c.Auth != auth || c.MachineCode != machine_code { - log.Fatalf("客户端接收到错误的服务端消息") + log.Printf("客户端接收到错误的服务端消息") return } switch data.Method { - case "pong": - // 收到心跳响应,更新最后pong时间 + case "ping": + // 收到服务端心跳,更新最后ping时间并回复pong c.mu.Lock() c.lastPong = time.Now() c.mu.Unlock() - log.Println("收到心跳响应") + log.Println("收到服务端心跳") + + // 回复pong + pongMsg := message.ServerMsg{ + ID: c.Auth + "::" + c.MachineCode, + Method: "pong", + Params: nil, + } + msgByte, err := json.Marshal(pongMsg) + if err != nil { + log.Printf("序列化pong消息失败:%v", err) + return + } + if err := c.send(msgByte); err != nil { + log.Printf("发送pong响应失败:%v", err) + } else { + log.Println("已回复pong") + } return case "mining.req": // 将 data.Params 重新序列化为 JSON,然后反序列化为 ConfigurationMiningMsg @@ -277,7 +305,7 @@ func (c *Client) handleReceiveMsg(msg []byte) { if err != nil { log.Printf("序列化 Params 失败:%v", err) sendMsg_str := message.ServerMsgResp{ - ID: c.Auth + "." + c.MachineCode, + ID: c.Auth + "::" + c.MachineCode, Result: false, Data: fmt.Errorf("序列化 Params 失败:%v", err), } @@ -291,7 +319,7 @@ func (c *Client) handleReceiveMsg(msg []byte) { if err != nil { log.Printf("解析挖矿配置消息失败:%v, Params: %s", err, string(paramsJSON)) sendMsg_str := message.ServerMsgResp{ - ID: c.Auth + "." + c.MachineCode, + ID: c.Auth + "::" + c.MachineCode, Result: false, Data: fmt.Errorf("解析挖矿配置消息失败:%v", err), } @@ -309,15 +337,16 @@ func (c *Client) handleReceiveMsg(msg []byte) { err = c.os.Mining(c.osName, mining_msg) if err != nil { sendMsg_str := message.ServerMsgResp{ - ID: c.Auth + "." + c.MachineCode, + ID: c.Auth + "::" + c.MachineCode, Result: false, Data: err.Error(), } sendMsg_byte, err := json.Marshal(sendMsg_str) if err != nil { - log.Fatalf("序列化%v失败:%v", sendMsg_str, err) + log.Printf("序列化%v失败:%v", sendMsg_str, err) return } + log.Println(string(sendMsg_byte)) c.send(sendMsg_byte) // 返回失败消息 return } @@ -332,13 +361,14 @@ func (c *Client) handleReceiveMsg(msg []byte) { WatchUrl: "", // 这里需要根据矿池自动生成 } sendMsg_str := message.ServerMsgResp{ - ID: c.Auth + "." + c.MachineCode, + ID: c.Auth + "::" + c.MachineCode, Result: true, Data: respData, + Method: "mining.resp", } sendMsg_byte, err := json.Marshal(sendMsg_str) if err != nil { - log.Fatalf("序列化%v失败:%v", sendMsg_str, err) + log.Printf("序列化%v失败:%v", sendMsg_str, err) return } c.send(sendMsg_byte) // 返回成功消息 @@ -379,45 +409,24 @@ func (c *Client) monitorMiningTask(cfg message.ConfigurationMiningMsg) { } } -// startHeartbeat 启动心跳检查 +// startHeartbeat 启动心跳检查(监控是否收到服务端的ping) func (c *Client) startHeartbeat() { - ticker := time.NewTicker(30 * time.Second) // 每30秒发送一次心跳 + ticker := time.NewTicker(30 * time.Second) // 每30秒检查一次 defer ticker.Stop() for { select { case <-ticker.C: - // 检查是否超过60秒未收到pong响应 + // 检查是否超过60秒未收到服务端的ping c.mu.Lock() lastPong := c.lastPong - conn := c.ServerConn c.mu.Unlock() - if time.Since(lastPong) > 60*time.Second { - log.Println("超过60秒未收到心跳响应,连接可能已断开") + if time.Since(lastPong) > 60*time.Minute { + log.Println("超过60分钟未收到服务端心跳,连接可能已断开") c.reconnect() return } - - // 发送心跳 - if conn != nil { - pingMsg := message.ServerMsg{ - ID: c.Auth + "." + c.MachineCode, - Method: "ping", - Params: nil, - } - msgByte, err := json.Marshal(pingMsg) - if err != nil { - log.Printf("序列化心跳消息失败:%v", err) - continue - } - if err := c.send(msgByte); err != nil { - log.Printf("发送心跳失败:%v", err) - c.reconnect() - return - } - log.Println("发送心跳") - } case <-c.stopHeartbeat: return } diff --git a/internal/db/db.go b/internal/db/db.go index d3d03c0..a536e4f 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -18,7 +18,7 @@ func NewSQLiteServer() *SQLiteServer { // Open (or create) the SQLite database db, err := sql.Open("sqlite3", "./mining_task.db") if err != nil { - log.Fatal(err) + log.Println(err) return nil } @@ -29,7 +29,7 @@ func NewSQLiteServer() *SQLiteServer { // Initialize the 'task' table if err := s.initTaskTable(); err != nil { - log.Fatal(err) + log.Println(err) return nil } @@ -79,7 +79,7 @@ func (s *SQLiteServer) LoadMiningTask() (bool, message.ConfigurationMiningMsg) { // Query the database rows, err := s.DB.Query(str, params...) if err != nil { - log.Fatal(err) + log.Println(err) } defer rows.Close() @@ -89,7 +89,7 @@ func (s *SQLiteServer) LoadMiningTask() (bool, message.ConfigurationMiningMsg) { // Scan the row into the task structure err := rows.Scan(&task.Coin, &task.Algo, &task.Pool, &task.WalletMining, &task.PoolUrl, &task.WalletAddress, &task.PoolUser, &task.WorkerID, &task.EndTimestamp) if err != nil { - log.Fatal(err) + log.Println(err) } // Check if there's more than one row diff --git a/internal/proxy/ali/config.conf b/internal/proxy/ali/config.conf new file mode 100644 index 0000000..22b59aa --- /dev/null +++ b/internal/proxy/ali/config.conf @@ -0,0 +1,5 @@ +[url] +# 消息进来的端口,即监听端口 +in=:3333 +# 消息发出去的端口,即转发端口 +out=47.129.22.53:21000 \ No newline at end of file diff --git a/internal/proxy/ali/main b/internal/proxy/ali/main new file mode 100644 index 0000000..1138c9a Binary files /dev/null and b/internal/proxy/ali/main differ diff --git a/internal/proxy/ali/main.go b/internal/proxy/ali/main.go new file mode 100644 index 0000000..e5adc2c --- /dev/null +++ b/internal/proxy/ali/main.go @@ -0,0 +1,80 @@ +package main + +import ( + "io" + "log" + "net" + "os" + "strings" + + "gopkg.in/ini.v1" +) + +func readConfig() (string, string) { + cfg, err := ini.Load("config.conf") + if err != nil { + log.Fatalf("无法读取配置文件: %v", err) + os.Exit(1) + } + section := cfg.Section("url") + + minerPort := strings.Trim(section.Key("in").String(), `""`) + minerPoolAddr := strings.Trim(section.Key("out").String(), `""`) + + return minerPort, minerPoolAddr +} + +var minerPort, minerPoolAddr = readConfig() + +// 处理矿机请求的函数 +func handleMinerConnection(minerConn net.Conn) { + defer minerConn.Close() + log.Println("有矿机接入") + // 连接到矿池 + poolConn, err := net.Dial("tcp", minerPoolAddr) + if err != nil { + log.Printf("无法连接到矿池: %v", err) + return + } + defer poolConn.Close() + + // 启动两个 goroutine:一个从矿机接收数据并转发到矿池,另一个从矿池接收数据并转发回矿机 + go transferData(minerConn, poolConn) + go transferData(poolConn, minerConn) + + // 保持服务运行,直到矿机或矿池关闭连接 + select {} +} + +// 数据转发函数:从源连接读取数据并写入到目标连接 +func transferData(src net.Conn, dest net.Conn) { + _, err := io.Copy(dest, src) + if err != nil { + log.Printf("数据转发失败: %v", err) + } +} + +func main() { + // 设置代理服务监听端口 + listener, err := net.Listen("tcp", minerPort) + if err != nil { + log.Fatalf("无法启动监听服务: %v", err) + os.Exit(1) + } + defer listener.Close() + + log.Printf("代理服务启动,监听端口 %s\n", minerPort) + + // 不断接收来自矿机的连接 + for { + // 接受矿机连接 + minerConn, err := listener.Accept() + if err != nil { + log.Printf("接受连接失败: %v", err) + continue + } + + // 为每个矿机连接启动一个新的 goroutine 来处理 + go handleMinerConnection(minerConn) + } +} diff --git a/internal/proxy/aws/config.conf b/internal/proxy/aws/config.conf new file mode 100644 index 0000000..1e0f0b9 --- /dev/null +++ b/internal/proxy/aws/config.conf @@ -0,0 +1,5 @@ +[url] +# 消息进来的端口,即监听端口 +in=:21000 +# 消息发出去的端口,即转发端口 +out=stratum+tcp://nexa.m2pool.com:33333 \ No newline at end of file diff --git a/internal/proxy/aws/main.go b/internal/proxy/aws/main.go new file mode 100644 index 0000000..e5adc2c --- /dev/null +++ b/internal/proxy/aws/main.go @@ -0,0 +1,80 @@ +package main + +import ( + "io" + "log" + "net" + "os" + "strings" + + "gopkg.in/ini.v1" +) + +func readConfig() (string, string) { + cfg, err := ini.Load("config.conf") + if err != nil { + log.Fatalf("无法读取配置文件: %v", err) + os.Exit(1) + } + section := cfg.Section("url") + + minerPort := strings.Trim(section.Key("in").String(), `""`) + minerPoolAddr := strings.Trim(section.Key("out").String(), `""`) + + return minerPort, minerPoolAddr +} + +var minerPort, minerPoolAddr = readConfig() + +// 处理矿机请求的函数 +func handleMinerConnection(minerConn net.Conn) { + defer minerConn.Close() + log.Println("有矿机接入") + // 连接到矿池 + poolConn, err := net.Dial("tcp", minerPoolAddr) + if err != nil { + log.Printf("无法连接到矿池: %v", err) + return + } + defer poolConn.Close() + + // 启动两个 goroutine:一个从矿机接收数据并转发到矿池,另一个从矿池接收数据并转发回矿机 + go transferData(minerConn, poolConn) + go transferData(poolConn, minerConn) + + // 保持服务运行,直到矿机或矿池关闭连接 + select {} +} + +// 数据转发函数:从源连接读取数据并写入到目标连接 +func transferData(src net.Conn, dest net.Conn) { + _, err := io.Copy(dest, src) + if err != nil { + log.Printf("数据转发失败: %v", err) + } +} + +func main() { + // 设置代理服务监听端口 + listener, err := net.Listen("tcp", minerPort) + if err != nil { + log.Fatalf("无法启动监听服务: %v", err) + os.Exit(1) + } + defer listener.Close() + + log.Printf("代理服务启动,监听端口 %s\n", minerPort) + + // 不断接收来自矿机的连接 + for { + // 接受矿机连接 + minerConn, err := listener.Accept() + if err != nil { + log.Printf("接受连接失败: %v", err) + continue + } + + // 为每个矿机连接启动一个新的 goroutine 来处理 + go handleMinerConnection(minerConn) + } +} diff --git a/internal/src/linux/linux.go b/internal/src/linux/linux.go index 2f8234f..8625454 100644 --- a/internal/src/linux/linux.go +++ b/internal/src/linux/linux.go @@ -50,15 +50,12 @@ func CheckPermission() error { func NewLinuxClient(auth string) *LinuxClient { cfg, err := ini.Load("mining.linux.conf") if err != nil { - log.Fatalf("获取挖矿配置失败: %v", err) + log.Printf("获取挖矿配置失败: %v", err) log.Printf("客户端已退出,请重新检查配置文件(%s)是否存在", "mining.linux.conf") return nil } // 解析配置 var miningConfig message.MiningConfig - // 解析 [bzminer] 部分 - sectionBzMiner := cfg.Section("bzminer") - miningConfig.BzMinerPath = sectionBzMiner.Key("path").String() // 解析 [lolminer] 部分 sectionLolMiner := cfg.Section("lolminer") @@ -72,20 +69,11 @@ func NewLinuxClient(auth string) *LinuxClient { sectionProxy := cfg.Section("proxy") miningConfig.ProxyEnabled, _ = sectionProxy.Key("proxy").Bool() - if miningConfig.BzMinerPath != "" { - result := utils.CheckFileExists(miningConfig.BzMinerPath) - if !result { - log.Fatalf("未检测到bzminer挖矿软件的存在,请确认是否已经安装bzminer,并核对下列路径:%s", miningConfig.BzMinerPath) - log.Println("客户端已退出,确认路径后请重启客户端") - return nil - } - } - if miningConfig.LolMinerPath != "" { result := utils.CheckFileExists(miningConfig.LolMinerPath) if !result { - log.Fatalf("未检测到lolminer挖矿软件的存在,请确认是否已经安装lolminer,并核对下列路径:%s", miningConfig.LolMinerPath) - log.Println("客户端已退出,确认路径后请重启客户端") + log.Printf("未检测到lolminer挖矿软件的存在,请确认是否已经安装lolminer,并核对下列路径:%s", miningConfig.LolMinerPath) + log.Fatalln("客户端已退出,确认路径后请重启客户端") return nil } } @@ -93,8 +81,8 @@ func NewLinuxClient(auth string) *LinuxClient { if miningConfig.RigelPath != "" { result := utils.CheckFileExists(miningConfig.RigelPath) if !result { - log.Fatalf("未检测到rigel挖矿软件的存在,请确认是否已经安装rigel,并核对下列路径:%s", miningConfig.RigelPath) - log.Println("客户端已退出,确认路径后请重启客户端") + log.Printf("未检测到rigel挖矿软件的存在,请确认是否已经安装rigel,并核对下列路径:%s", miningConfig.RigelPath) + log.Fatalln("客户端已退出,确认路径后请重启客户端") return nil } } @@ -110,8 +98,8 @@ func NewLinuxClient(auth string) *LinuxClient { // 获取主机身份 mac, err := client.GetMACAddress() if err != nil { - log.Fatalln(err) - panic("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") + log.Println(err) + log.Fatalln("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") } client.MachineCode = mac client.ID = auth + "." + mac @@ -129,7 +117,7 @@ func (l *LinuxClient) initHistoryTask() { l.mu.Unlock() err := l.Mining(task) if err != nil { - log.Fatalf("重新开启挖矿任务失败,请手动检查:%v", err) + log.Printf("重新开启挖矿任务失败,请手动检查:%v", err) return } } else { @@ -279,7 +267,7 @@ ALGO=NEXA func (l *LinuxClient) lolminer(cfg message.ConfigurationMiningMsg) { l.mu.Lock() if l.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } l.Status = 1 @@ -303,14 +291,14 @@ func (l *LinuxClient) lolminer(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting lolMiner: %v", err) + log.Printf("Error starting lolMiner: %v", err) return } // 添加执行记录 go func() { err := l.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 lolMiner 的进程 ID @@ -344,7 +332,7 @@ func (l *LinuxClient) lolminer(cfg message.ConfigurationMiningMsg) { go func() { err := l.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() // 输出进程被杀死的信息 @@ -370,7 +358,7 @@ ALGO=NEXA func (l *LinuxClient) bzminer(cfg message.ConfigurationMiningMsg) { l.mu.Lock() if l.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } l.Status = 1 @@ -392,14 +380,14 @@ func (l *LinuxClient) bzminer(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting bzminer: %v", err) + log.Printf("Error starting bzminer: %v", err) return } // 添加执行记录 go func() { err := l.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 bzminer 的进程 ID @@ -432,7 +420,7 @@ func (l *LinuxClient) bzminer(cfg message.ConfigurationMiningMsg) { go func() { err := l.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() // 输出进程被杀死的信息 @@ -458,7 +446,7 @@ ALGO=nexapow func (l *LinuxClient) rigel(cfg message.ConfigurationMiningMsg) { l.mu.Lock() if l.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } l.Status = 1 @@ -481,14 +469,14 @@ func (l *LinuxClient) rigel(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting rigel: %v", err) + log.Printf("Error starting rigel: %v", err) return } // 添加执行记录 go func() { err := l.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 rigel 的进程 ID @@ -522,7 +510,7 @@ func (l *LinuxClient) rigel(cfg message.ConfigurationMiningMsg) { go func() { err := l.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() // 输出进程被结束的信息 diff --git a/internal/src/miningSoft/linux.go b/internal/src/miningSoft/linux.go new file mode 100644 index 0000000..6003180 --- /dev/null +++ b/internal/src/miningSoft/linux.go @@ -0,0 +1,77 @@ +package miningsoft + +import ( + "bufio" + "log" + "os/exec" + "path/filepath" + "strings" +) + +/* +XTM - Cuckaroo29 - lolMiner.exe --algo CR29 --pool xtm-c29.kryptex.network:7040 --user WALLET_ADDRESS/WORKER_NAME +CFX - Conflux - lolMiner.exe --algo OCTOPUS --pool cfx.kryptex.network:7027 --user WALLET_ADDRESS/WORKER_NAME +IRON - IronFish - lolMiner.exe --algo FISHHASH --pool iron.kryptex.network:7017 --user WALLET_ADDRESS.WORKER_NAME +NEXA - NexaPow - lolMiner.exe --algo NEXA --pool nexa.kryptex.network:7026 --user WALLET_ADDRESS/WORKER_NAME +KLS - Karlsen - lolMiner.exe --algo KARLSENV2 --pool kls.kryptex.network:7022 --user WALLET_ADDRESS/WORKER_NAME +ERG - Autolykos - lolMiner.exe --algo AUTOLYKOS2 --pool erg.kryptex.network:7021 --user WALLET_ADDRESS/WORKER_NAME +XEL - Xelishashv2 - rigel.exe -a xelishashv2 -o stratum+tcp://xel.kryptex.network:7019 -u WALLET_ADDRESS/WORKER_NAME +QUAI - QUAI - rigel.exe -a quai -o stratum+tcp://quai.kryptex.network:7035 -u WALLET_ADDRESS/WORKER_NAME +XNA - Neurai - rigel.exe -a kawpow --coin xna -o stratum+tcp://xna.kryptex.network:7024 -u WALLET_ADDRESS/WORKER_NAME +CLORE - KawPow - rigel.exe -a kawpow --coin clore -o stratum+tcp://clore.kryptex.network:7025 -u WALLET_ADDRESS/WORKER_NAME +RVN - Ravencoin - rigel.exe -a kawpow --coin rvn -o stratum+tcp://rvn.kryptex.network:7031 -u WALLET_ADDRESS/WORKER_NAME +*/ + +const SOFTNAME = "lolMiner" + +func StartMiner(soft_path, algo, pool, user, worker_id string, ch chan string) { + name := filepath.Join(soft_path, SOFTNAME) + args := []string{"--algo", algo, "--pool", pool, "--user", user + "/" + worker_id} + + cmd := exec.Command(name, args...) + cmd.Dir = soft_path + + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Printf("获取 lolMiner 标准输出失败: %v", err) + return + } + // stderr, err := cmd.StderrPipe() + // if err != nil { + // log.Printf("获取 lolMiner 错误输出失败: %v", err) + // return + // } + log.Printf("执行命令:%s %s", name, strings.Join(args, " ")) + // 启动lolminer + err = cmd.Start() + if err != nil { + log.Printf("Error starting lolMiner: %v", err) + return + } + + // 处理标准输出 + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + line := scanner.Text() + switch { + case strings.Contains(line, "Lost connection to stratum"): + log.Printf("lolMiner 检测到矿池断开连接: %s", line) + case strings.Contains(line, "Average speed (15s)"): + if strings.Contains(line, "Average speed (15s): 0.00 Mh/s") { + log.Printf("lolMiner 检测到没有算力: %s", line) + } else { + // 有算力 + } + case strings.Contains(line, "defect stratum message"): + log.Printf("lolMiner 检测到 stratum 协议错误: %s", line) + + default: + log.Printf("lolMiner 输出: %s", line) + } + } + if err := scanner.Err(); err != nil { + log.Printf("读取 lolMiner 标准输出失败: %v", err) + } + }() +} diff --git a/internal/src/miningSoft/windows.go b/internal/src/miningSoft/windows.go new file mode 100644 index 0000000..bf10b41 --- /dev/null +++ b/internal/src/miningSoft/windows.go @@ -0,0 +1 @@ +package miningsoft diff --git a/internal/src/src.go b/internal/src/src.go index 9dc2baa..fdc9c79 100644 --- a/internal/src/src.go +++ b/internal/src/src.go @@ -68,6 +68,6 @@ func (s *SystemServer) StopMining(osName string) { if srv, ok := s.systems[osName]; ok { srv.StopMining() } else { - log.Fatalf("错误的操作系统:%s", osName) + log.Printf("错误的操作系统:%s", osName) } } diff --git a/internal/src/windows/windows.go b/internal/src/windows/windows.go index 4f480ae..e4a97b4 100644 --- a/internal/src/windows/windows.go +++ b/internal/src/windows/windows.go @@ -46,7 +46,7 @@ func CheckPermission() error { func NewWindowsClient(auth string) *WindowsClient { cfg, err := ini.Load("mining.windows.conf") if err != nil { - log.Fatalf("获取挖矿配置失败: %v", err) + log.Printf("获取挖矿配置失败: %v", err) log.Printf("客户端已退出,请重新检查配置文件(%s)是否存在", "mining.windows.conf") return nil } @@ -68,20 +68,11 @@ func NewWindowsClient(auth string) *WindowsClient { sectionProxy := cfg.Section("proxy") miningConfig.ProxyEnabled, _ = sectionProxy.Key("proxy").Bool() - if miningConfig.BzMinerPath != "" { - result := utils.CheckFileExists(miningConfig.BzMinerPath) - if !result { - log.Fatalf("未检测到bzminer挖矿软件的存在,请确认是否已经安装bzminer,并核对下列路径:%s", miningConfig.BzMinerPath) - log.Println("客户端已退出,确认路径后请重启客户端") - return nil - } - } - if miningConfig.LolMinerPath != "" { result := utils.CheckFileExists(miningConfig.LolMinerPath) if !result { - log.Fatalf("未检测到lolminer挖矿软件的存在,请确认是否已经安装lolminer,并核对下列路径:%s", miningConfig.LolMinerPath) - log.Println("客户端已退出,确认路径后请重启客户端") + log.Printf("未检测到lolminer挖矿软件的存在,请确认是否已经安装lolminer,并核对下列路径:%s", miningConfig.LolMinerPath) + log.Fatalln("客户端已退出,确认路径后请重启客户端") return nil } } @@ -89,8 +80,8 @@ func NewWindowsClient(auth string) *WindowsClient { if miningConfig.RigelPath != "" { result := utils.CheckFileExists(miningConfig.RigelPath) if !result { - log.Fatalf("未检测到rigel挖矿软件的存在,请确认是否已经安装rigel,并核对下列路径:%s", miningConfig.RigelPath) - log.Println("客户端已退出,确认路径后请重启客户端") + log.Printf("未检测到rigel挖矿软件的存在,请确认是否已经安装rigel,并核对下列路径:%s", miningConfig.RigelPath) + log.Fatalln("客户端已退出,确认路径后请重启客户端") return nil } } @@ -105,8 +96,8 @@ func NewWindowsClient(auth string) *WindowsClient { mac, err := client.GetMACAddress() if err != nil { - log.Fatalln(err) - panic("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") + log.Println(err) + log.Fatalln("获取当前主机信息失败,程序已退出,请检查网络后重新启动本客户端。") } client.MachineCode = mac @@ -125,7 +116,7 @@ func (w *WindowsClient) initHistoryTask() { w.mu.Unlock() err := w.Mining(task) if err != nil { - log.Fatalf("重新开启挖矿任务失败,请手动检查:%v", err) + log.Printf("重新开启挖矿任务失败,请手动检查:%v", err) return } } else { @@ -257,6 +248,9 @@ func (w *WindowsClient) GetMACAddress() (string, error) { return "", fmt.Errorf("获取到的主机 UUID 无效: %q", uuid) } + // 将 UUID 中的 "." 替换成 "::" + // uuid = strings.Replace(uuid, ".", "::", -1) + // 统一转换为大写,去掉花括号 uuid = strings.Trim(uuid, "{}") uuid = strings.ToUpper(uuid) @@ -271,7 +265,7 @@ Windows 下使用 lolMiner.exe func (w *WindowsClient) lolminer(cfg message.ConfigurationMiningMsg) { w.mu.Lock() if w.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } w.Status = 1 @@ -295,14 +289,14 @@ func (w *WindowsClient) lolminer(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting lolMiner: %v", err) + log.Printf("Error starting lolMiner: %v", err) return } // 添加执行记录 go func() { err := w.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 lolMiner 的进程 ID @@ -327,7 +321,7 @@ func (w *WindowsClient) lolminer(cfg message.ConfigurationMiningMsg) { go func() { err := w.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() } else { @@ -343,7 +337,7 @@ func (w *WindowsClient) lolminer(cfg message.ConfigurationMiningMsg) { go func() { err := w.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() } @@ -360,7 +354,7 @@ Windows 下使用 bzminer.exe func (w *WindowsClient) bzminer(cfg message.ConfigurationMiningMsg) { w.mu.Lock() if w.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } w.Status = 1 @@ -382,14 +376,14 @@ func (w *WindowsClient) bzminer(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting bzminer: %v", err) + log.Printf("Error starting bzminer: %v", err) return } // 添加执行记录 go func() { err := w.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 bzminer 的进程 ID @@ -425,7 +419,7 @@ func (w *WindowsClient) bzminer(cfg message.ConfigurationMiningMsg) { go func() { err := w.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() // 输出进程被结束的信息 @@ -444,7 +438,7 @@ Windows 下使用 rigel.exe func (w *WindowsClient) rigel(cfg message.ConfigurationMiningMsg) { w.mu.Lock() if w.Status != 2 { - log.Fatalf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) + log.Printf("当前还有挖矿任务正在进行中:币=%s, 算法=%s, 矿池=%s, 截止时间=%d", cfg.Coin, cfg.Algo, cfg.Pool, cfg.EndTimestamp) return } w.Status = 1 @@ -467,14 +461,14 @@ func (w *WindowsClient) rigel(cfg message.ConfigurationMiningMsg) { // 启动进程 err := cmd.Start() if err != nil { - log.Fatalf("Error starting rigel: %v", err) + log.Printf("Error starting rigel: %v", err) return } // 添加执行记录 go func() { err := w.db.InsertMiningTask(cfg) if err != nil { - log.Fatalf("本次挖矿任务记录失败:%v", err) + log.Printf("本次挖矿任务记录失败:%v", err) } }() // 获取 rigel 的进程 ID @@ -510,7 +504,7 @@ func (w *WindowsClient) rigel(cfg message.ConfigurationMiningMsg) { go func() { err := w.db.FinishMiningTask(cfg) if err != nil { - log.Fatalf("修改执行记录失败:%v", err) + log.Printf("修改执行记录失败:%v", err) } }() // 输出进程被结束的信息 diff --git a/internal/updater/updater.go b/internal/updater/updater.go index ca2f11e..5a00d1b 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -67,7 +67,7 @@ func CheckAndUpdate(remoteBaseURL string, currentVersion string) (bool, error) { // fetchRemoteVersion 从远程获取版本号 func fetchRemoteVersion(remoteBaseURL string) (string, error) { - versionURL := fmt.Sprintf("%s/current_version", remoteBaseURL) + versionURL := fmt.Sprintf("%s/user/getClientVersion", remoteBaseURL) resp, err := http.Get(versionURL) if err != nil {