300 lines
8.1 KiB
Go
300 lines
8.1 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"m2pool-payment/internal/blockchain"
|
|
"m2pool-payment/internal/blockchain/eth"
|
|
"m2pool-payment/internal/crypto"
|
|
message "m2pool-payment/internal/msg"
|
|
rmq "m2pool-payment/internal/queue"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
const MSG_KEY string = "9f3c7a12"
|
|
|
|
// 状态码常量
|
|
const (
|
|
STATUS_FAILED = 0 // 失败
|
|
STATUS_SUCCESS = 1 // 成功
|
|
STATUS_PENDING = 2 // 待确认
|
|
STATUS_VERIFY_FAILED = 3 // 验证失败
|
|
)
|
|
|
|
type ServerCtx struct {
|
|
msgKey string
|
|
Config message.Config
|
|
blockChainServer *blockchain.BlockChainServer
|
|
rmqServer *rmq.RabbitMQServer
|
|
}
|
|
|
|
var s_ctx ServerCtx
|
|
|
|
// verifyMessage 验证消息签名
|
|
func verifyMessage(timestamp uint64, sign string) bool {
|
|
hash_byte := crypto.Sha256Hash(fmt.Sprintf("%x", timestamp) + MSG_KEY)
|
|
hash := hex.EncodeToString(hash_byte)
|
|
return hash == sign
|
|
}
|
|
|
|
func loadConfig(msgKey string) {
|
|
file, err := os.ReadFile("config.json")
|
|
if err != nil {
|
|
panic(fmt.Sprintf("读取配置文件失败: %v", err))
|
|
}
|
|
|
|
err = json.Unmarshal(file, &s_ctx.Config)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("解析配置文件失败: %v", err))
|
|
}
|
|
|
|
log.Printf("✅ 配置加载成功: RPC=%s, WS=%s",
|
|
s_ctx.Config.ETHConfig.RpcURL, s_ctx.Config.ETHConfig.WsURL)
|
|
|
|
s_ctx.msgKey = msgKey
|
|
}
|
|
|
|
func initBlockChainServer() {
|
|
// 初始化节点服务
|
|
node_server := blockchain.NewBlockChainServer()
|
|
// 初始化ETH节点
|
|
eth_node, err := eth.NewETHNode(s_ctx.Config.ETHConfig, "m2pool")
|
|
if err != nil {
|
|
log.Fatalf("ETH-Node Start error: %v", err)
|
|
}
|
|
// 注册ETH节点
|
|
node_server.RegisterChain("ETH", eth_node)
|
|
// 将所有注册的blockChainServer绑定至server
|
|
s_ctx.blockChainServer = node_server
|
|
|
|
log.Println("✅ 区块链服务初始化完成")
|
|
}
|
|
|
|
func initRmqServer() {
|
|
// 初始化rmq服务
|
|
rmq_server, err := rmq.NewRabbitMQServer(s_ctx.Config.RMQConfig)
|
|
if err != nil {
|
|
log.Fatalf("RabbitMQ Server Start error: %v", err)
|
|
}
|
|
// 将rmq服务绑定至server
|
|
s_ctx.rmqServer = rmq_server
|
|
|
|
log.Printf("✅ RabbitMQ服务初始化完成: %s", s_ctx.Config.RMQConfig.SubAddr)
|
|
}
|
|
|
|
func handleTopupMsg() {
|
|
s_ctx.rmqServer.OnTopupMsg = func(msg message.TopupMsg_req) {
|
|
msg.Address = strings.ToLower(msg.Address)
|
|
|
|
// 验证签名
|
|
if !verifyMessage(msg.Timestamp, msg.Sign) {
|
|
err := s_ctx.rmqServer.PublishTopupResp(message.TopupMsg_resp{
|
|
Address: msg.Address,
|
|
Status: STATUS_VERIFY_FAILED,
|
|
Chain: msg.Chain,
|
|
Symbol: msg.Symbol,
|
|
Amount: 0,
|
|
TxHash: "",
|
|
})
|
|
if err != nil {
|
|
log.Printf("❌ 发布充值失败响应失败: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 添加监听地址
|
|
s_ctx.blockChainServer.AddAddress(msg.Chain, msg.Address, msg)
|
|
}
|
|
}
|
|
|
|
func handleWithdrawMsg() {
|
|
s_ctx.rmqServer.OnWithdrawMsg = func(msg message.WithdrawMsg_req) {
|
|
msg.FromAddress = strings.ToLower(msg.FromAddress)
|
|
msg.ToAddress = strings.ToLower(msg.ToAddress)
|
|
|
|
// 验证签名
|
|
if !verifyMessage(msg.Timestamp, msg.Sign) {
|
|
err := s_ctx.rmqServer.PublishWithdrawResp(message.WithdrawMsg_resp{
|
|
QueueId: msg.QueueId,
|
|
Status: STATUS_VERIFY_FAILED,
|
|
Chain: msg.Chain,
|
|
Symbol: msg.Symbol,
|
|
Amount: 0,
|
|
TxHash: "",
|
|
})
|
|
if err != nil {
|
|
log.Printf("❌ 发布提现失败响应失败: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 执行转账
|
|
err := s_ctx.blockChainServer.Transfer(msg.Chain, msg.Symbol, msg)
|
|
if err != nil {
|
|
log.Printf("❌ 提现转账失败: %v", err)
|
|
// 发送失败响应
|
|
s_ctx.rmqServer.PublishWithdrawResp(message.WithdrawMsg_resp{
|
|
QueueId: msg.QueueId,
|
|
Status: STATUS_FAILED,
|
|
Amount: msg.Amount,
|
|
Chain: msg.Chain,
|
|
Symbol: msg.Symbol,
|
|
TxHash: "",
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func handlePayMsg() {
|
|
s_ctx.rmqServer.OnPayMsg = func(msg message.PayMsg_req) {
|
|
msg.FromAddress = strings.ToLower(msg.FromAddress)
|
|
msg.ToAddress = strings.ToLower(msg.ToAddress)
|
|
|
|
// 验证签名
|
|
if !verifyMessage(msg.Timestamp, msg.Sign) {
|
|
err := s_ctx.rmqServer.PublishPayResp(message.PayMsg_resp{
|
|
QueueId: msg.QueueId,
|
|
Status: STATUS_VERIFY_FAILED,
|
|
Amount: msg.Amount,
|
|
Chain: msg.Chain,
|
|
Symbol: msg.Symbol,
|
|
OrderId: msg.OrderId,
|
|
TxHash: "",
|
|
})
|
|
if err != nil {
|
|
log.Printf("❌ 发布支付失败响应失败: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 执行转账
|
|
err := s_ctx.blockChainServer.Transfer(msg.Chain, msg.Symbol, msg)
|
|
if err != nil {
|
|
log.Printf("❌ 支付转账失败: %v", err)
|
|
// 发送失败响应
|
|
s_ctx.rmqServer.PublishPayResp(message.PayMsg_resp{
|
|
QueueId: msg.QueueId,
|
|
Status: STATUS_FAILED,
|
|
Amount: msg.Amount,
|
|
Chain: msg.Chain,
|
|
Symbol: msg.Symbol,
|
|
OrderId: msg.OrderId,
|
|
TxHash: "",
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func initRmqListen() {
|
|
// ================== 设置 RabbitMQ 消息处理回调 ==================
|
|
// 先设置所有回调(同步执行,避免竞态)
|
|
handleTopupMsg()
|
|
handleWithdrawMsg()
|
|
handlePayMsg()
|
|
|
|
// 回调设置完成后,再启动 RabbitMQ 监听
|
|
if err := s_ctx.rmqServer.Start(); err != nil {
|
|
log.Fatalf("启动 RabbitMQ 监听失败: %v", err)
|
|
}
|
|
log.Println("✅ RabbitMQ 监听启动完成")
|
|
}
|
|
|
|
func handleChainEvent(chainEventCh chan any) {
|
|
for event := range chainEventCh {
|
|
// 添加 panic 恢复,防止单个消息处理错误导致整个 goroutine 退出
|
|
func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
log.Printf("❌ 处理链上事件 panic: %v, event: %+v", r, event)
|
|
}
|
|
}()
|
|
|
|
// 根据消息类型发送不同的响应
|
|
switch msg := event.(type) {
|
|
case message.TopupMsg_resp:
|
|
// 充值确认
|
|
if msg.Status == STATUS_PENDING {
|
|
log.Printf("📨 [链上] 充值待确认: Address=%s, Amount=%.2f, TxHash=%s",
|
|
msg.Address, msg.Amount, msg.TxHash)
|
|
} else {
|
|
log.Printf("✅ [链上] 充值确认: Address=%s, Amount=%.2f, TxHash=%s, Status=%d",
|
|
msg.Address, msg.Amount, msg.TxHash, msg.Status)
|
|
}
|
|
err := s_ctx.rmqServer.PublishTopupResp(msg)
|
|
if err != nil {
|
|
log.Printf("❌ 发送充值响应失败: %v", err)
|
|
}
|
|
|
|
case message.WithdrawMsg_resp:
|
|
// 提现确认
|
|
log.Printf("✅ [链上] 提现确认: QueueId=%s, Amount=%.2f, TxHash=%s, Status=%d",
|
|
msg.QueueId, msg.Amount, msg.TxHash, msg.Status)
|
|
err := s_ctx.rmqServer.PublishWithdrawResp(msg)
|
|
if err != nil {
|
|
log.Printf("❌ 发送提现响应失败: %v", err)
|
|
}
|
|
|
|
case message.PayMsg_resp:
|
|
// 支付确认
|
|
log.Printf("✅ [链上] 支付确认: QueueId=%s, OrderId=%s, Amount=%.2f, TxHash=%s, Status=%d",
|
|
msg.QueueId, msg.OrderId, msg.Amount, msg.TxHash, msg.Status)
|
|
err := s_ctx.rmqServer.PublishPayResp(msg)
|
|
if err != nil {
|
|
log.Printf("❌ 发送支付响应失败: %v", err)
|
|
}
|
|
|
|
default:
|
|
log.Printf("⚠️ 未知消息类型: %T", event)
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func Start(msgKey string) {
|
|
log.Println("========================================")
|
|
log.Println("🚀 M2Pool Payment System Starting...")
|
|
log.Println("========================================")
|
|
|
|
// 加载配置
|
|
loadConfig(msgKey)
|
|
|
|
// ================== 初始化区块链节点 ==================
|
|
initBlockChainServer()
|
|
|
|
// ================== 初始化 RabbitMQ 服务 ==================
|
|
initRmqServer()
|
|
|
|
// ================== 启动链上事件监听通道 ==================
|
|
chainEventCh := make(chan any, 1000) // 增加缓冲区,避免高并发丢消息
|
|
go s_ctx.blockChainServer.Listen("ETH", "USDT", chainEventCh)
|
|
|
|
// ================== 启动 RabbitMQ 监听 ==================
|
|
initRmqListen()
|
|
|
|
// ================== 处理链上确认事件 ==================
|
|
go handleChainEvent(chainEventCh)
|
|
|
|
log.Println("========================================")
|
|
log.Println("🎉 所有服务启动完成!")
|
|
log.Println("========================================")
|
|
// ================== 等待退出信号 ==================
|
|
sigCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
<-sigCh
|
|
|
|
// 优雅关闭
|
|
log.Println("========================================")
|
|
log.Println("🛑 收到退出信号,正在关闭服务...")
|
|
log.Println("========================================")
|
|
|
|
s_ctx.blockChainServer.Stop("ETH")
|
|
s_ctx.rmqServer.Close()
|
|
|
|
log.Println("👋 服务已全部关闭")
|
|
}
|