package server import ( "encoding/json" "fmt" "net" "os" "proxy/internal/miner" "proxy/internal/zmq" "sync" "time" ) const TOPIC = "[server]: " type Config struct { Coin string `json:"coin"` ZmqAddr string `json:"zmqAddr"` TcpAddr string `json:"tcpAddr"` DefaultAddr string `json:"proxyAddr"` } type ProxyCtx struct { Coin string mu sync.RWMutex Cfg Config Listener net.Listener MinerConn []*miner.Miner ProxyList map[string]string } func initConfig() Config { data, err := os.ReadFile("./config.json") if err != nil { panic(TOPIC + "配置读取失败: " + err.Error()) } var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { panic(TOPIC + "配置解析失败: " + err.Error()) } return cfg } func newProxy() *ProxyCtx { cfg := initConfig() listener, err := net.Listen("tcp", cfg.TcpAddr) if err != nil { panic(TOPIC + "监听失败: " + err.Error()) } return &ProxyCtx{ Coin: cfg.Coin, Cfg: cfg, Listener: listener, MinerConn: []*miner.Miner{}, ProxyList: make(map[string]string), } } func (p *ProxyCtx) handleMinerConnect() { fmt.Println(TOPIC, "TCP 服务已启动,监听地址:", p.Cfg.TcpAddr) for { conn, err := p.Listener.Accept() if err != nil { fmt.Println(TOPIC+"接收连接失败:", err) continue } go func(conn net.Conn) { ch := make(chan string, 1) minerObj, err := miner.NewMiner(p.Coin, p.Cfg.DefaultAddr, conn) if err != nil { fmt.Println(TOPIC, "创建 Miner 失败:", err) conn.Close() return } go minerObj.HandleMinerMsg(ch) select { case userSign := <-ch: p.mu.RLock() addr, ok := p.ProxyList[userSign] p.mu.RUnlock() if ok { minerObj.ChangePoolAddress(addr) } p.mu.Lock() p.MinerConn = append(p.MinerConn, minerObj) p.mu.Unlock() go minerObj.HandlePoolMsg() case <-time.After(10 * time.Second): fmt.Println(TOPIC, "超时未收到矿工认证,关闭连接") minerObj.MinerConn.Close() minerObj.PoolConn.Close() } }(conn) } } func (p *ProxyCtx) startZMQ() { zmq.StartZMQ(p.Cfg.ZmqAddr, p.ProxyList, &p.mu) } func StartProxy() { p := newProxy() // 启动 ZeroMQ 控制线程 go p.startZMQ() // 启动 TCP 服务 p.handleMinerConnect() }