proxy test ver
This commit is contained in:
commit
cfda4d8425
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"coin": "alph",
|
||||
"zmqAddr": "tcp://127.0.0.1:39001",
|
||||
"tcpAddr": "0.0.0.0:39002",
|
||||
"proxyAddr": "stratum+tcp://alph.m2pool.com:33390"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
server "proxy/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
server.StartProxy()
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module proxy
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require github.com/zeromq/goczmq v4.1.0+incompatible
|
|
@ -0,0 +1,2 @@
|
|||
github.com/zeromq/goczmq v4.1.0+incompatible h1:cGVQaU6kIwwrGso0Pgbl84tzAz/h7FJ3wYQjSonjFFc=
|
||||
github.com/zeromq/goczmq v4.1.0+incompatible/go.mod h1:1uZybAJoSRCvZMH2rZxEwWBSmC4T7CB/xQOfChwPEzg=
|
|
@ -0,0 +1,130 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"proxy/internal/msg"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const topic string = "[miner]:"
|
||||
|
||||
type Miner struct {
|
||||
sync.Mutex
|
||||
Coin string
|
||||
ID string // user + miner
|
||||
PoolConn net.Conn
|
||||
MinerConn net.Conn
|
||||
PoolAddress string
|
||||
}
|
||||
|
||||
func NewMiner(coin string, poolAddress string, minerConn net.Conn) (*Miner, error) {
|
||||
poolConn, err := net.Dial("tcp", poolAddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pool连接失败: %v", err)
|
||||
}
|
||||
|
||||
return &Miner{
|
||||
Coin: coin,
|
||||
PoolConn: poolConn,
|
||||
MinerConn: minerConn,
|
||||
PoolAddress: poolAddress,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 动态切换矿池地址并建立新连接
|
||||
func (m *Miner) ChangePoolAddress(newAddress string) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// 尝试建立新连接
|
||||
newConn, err := net.Dial("tcp", newAddress)
|
||||
if err != nil {
|
||||
fmt.Println("切换pool连接失败:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 关闭旧连接
|
||||
if m.PoolConn != nil {
|
||||
_ = m.PoolConn.Close()
|
||||
}
|
||||
|
||||
m.PoolConn = newConn
|
||||
m.PoolAddress = newAddress
|
||||
|
||||
fmt.Println("成功切换矿池地址为:", newAddress)
|
||||
}
|
||||
|
||||
// 矿工消息处理
|
||||
func (m *Miner) HandleMinerMsg(ch chan string) {
|
||||
defer m.MinerConn.Close()
|
||||
defer m.PoolConn.Close()
|
||||
|
||||
reader := bufio.NewReader(m.MinerConn)
|
||||
sent := false // 保证 userSign 只发送一次
|
||||
|
||||
for {
|
||||
msgStr, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("miner消息读取失败:", err)
|
||||
return
|
||||
}
|
||||
// fmt.Println("从矿工收到消息:", msgStr)
|
||||
switch m.Coin {
|
||||
case "nexa":
|
||||
//
|
||||
default:
|
||||
var msg msg.Authorize_msg
|
||||
if err := json.Unmarshal([]byte(msgStr), &msg); err == nil &&
|
||||
msg.Method == "mining.authorize" && len(msg.Params) >= 1 && !sent {
|
||||
parts := strings.Split(msg.Params[0], ".")
|
||||
if len(parts) >= 2 {
|
||||
userSign := parts[0] + "-" + parts[1]
|
||||
select {
|
||||
case ch <- userSign:
|
||||
sent = true
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
fmt.Println(topic+"mining.authorize解析user-miner错误\n", err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if m.PoolConn != nil {
|
||||
_, err = m.PoolConn.Write([]byte(msgStr))
|
||||
if err != nil {
|
||||
fmt.Println("转发到pool失败:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 矿池消息处理
|
||||
func (m *Miner) HandlePoolMsg() {
|
||||
defer m.MinerConn.Close()
|
||||
defer m.PoolConn.Close()
|
||||
|
||||
reader := bufio.NewReader(m.PoolConn)
|
||||
for {
|
||||
poolMsg, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("pool消息读取失败:", err)
|
||||
return
|
||||
}
|
||||
// fmt.Println("从矿池收到消息:", poolMsg)
|
||||
|
||||
if m.MinerConn != nil {
|
||||
_, err = m.MinerConn.Write([]byte(poolMsg))
|
||||
if err != nil {
|
||||
fmt.Println("转发到miner失败:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package msg
|
||||
|
||||
type ZmqMsg struct {
|
||||
MethodID int `json:"methodId"` //0(add), 1(delete)
|
||||
ID string `json:"id"` // user-miner
|
||||
Address string `json:"address"` // 转发目标地址
|
||||
}
|
||||
|
||||
type Authorize_msg struct {
|
||||
ID int `json:"id"`
|
||||
Method string `json:"method"`
|
||||
Params []string
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
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()
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package zmq
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"proxy/internal/msg"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/zeromq/goczmq"
|
||||
)
|
||||
|
||||
func initZmqPull(sub_to string) *goczmq.Sock {
|
||||
pull_ch, err := goczmq.NewPull(sub_to)
|
||||
if err != nil {
|
||||
fmt.Println("[zmq]:", err)
|
||||
}
|
||||
//pull_ch.SetMaxmsgsize(1024 * 1024 * 8)
|
||||
return pull_ch
|
||||
}
|
||||
|
||||
func handleZmqMsg(zmqMsg []byte, proxyList map[string]string, proxyListLock *sync.RWMutex) {
|
||||
var data msg.ZmqMsg
|
||||
if err := json.Unmarshal(zmqMsg, &data); err != nil {
|
||||
fmt.Println("[zmq]:", err)
|
||||
return
|
||||
}
|
||||
proxyListLock.Lock()
|
||||
// MethodID: 0(add), 1(delete)
|
||||
if data.MethodID == 0 {
|
||||
proxyList[data.ID] = data.Address
|
||||
} else {
|
||||
delete(proxyList, data.ID)
|
||||
}
|
||||
proxyListLock.Unlock()
|
||||
}
|
||||
|
||||
func StartZMQ(zmqAddr string, proxyList map[string]string, proxyListLock *sync.RWMutex) {
|
||||
conn := initZmqPull(zmqAddr)
|
||||
for {
|
||||
zmqMsg, _, err := conn.RecvFrame()
|
||||
if err != nil {
|
||||
fmt.Println("[zmq recv]:", err)
|
||||
time.Sleep(time.Second) // 防止CPU空转
|
||||
continue
|
||||
}
|
||||
handleZmqMsg(zmqMsg, proxyList, proxyListLock)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue