Files
exchange_go/cmd/bitget/bitget.go
2025-10-14 19:58:59 +08:00

272 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package bitget
import (
"context"
"fmt"
"go-admin/app/admin/models"
"go-admin/common/const/rediskey"
"go-admin/common/database"
"go-admin/common/global"
"go-admin/common/helper"
"go-admin/common/storage"
"go-admin/config/serverinit"
"go-admin/pkg/utility"
"go-admin/services/bitgetservice"
"go-admin/services/fileservice"
"os"
"os/signal"
"strconv"
"time"
ext "go-admin/config"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/config/source/file"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk"
"github.com/go-admin-team/go-admin-core/sdk/config"
"github.com/go-admin-team/go-admin-core/sdk/pkg"
"github.com/spf13/cobra"
"gorm.io/gorm"
)
var (
configYml string
StartCmd = &cobra.Command{
Use: "bitget",
Short: "Start Bitget service (market data + user private)",
Example: "go-admin bitget -c config/settings.yml",
SilenceUsage: true,
PreRun: func(cmd *cobra.Command, args []string) {
setup()
},
RunE: func(cmd *cobra.Command, args []string) error {
return run()
},
}
)
func init() {
StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
}
func setup() {
// 注入配置扩展项
config.ExtendConfig = &ext.ExtConfig
//1. 读取配置
config.Setup(
file.NewSource(file.WithPath(configYml)),
database.Setup,
storage.Setup,
)
//注册监听函数
queue := sdk.Runtime.GetMemoryQueue("")
queue.Register(global.LoginLog, models.SaveLoginLog)
queue.Register(global.OperateLog, models.SaveOperaLog)
go queue.Run()
usageStr := `starting Bitget service (market data + user private)...`
logger.Info(usageStr)
}
func run() error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var db *gorm.DB
dbs := sdk.Runtime.GetDb()
for _, item := range dbs {
db = item
break
}
defaultInit(db, ctx)
utility.SafeGo(func() {
// 启动定时任务
clearLogJob(db, ctx)
})
//自动重启websocket
utility.SafeGo(func() {
reconnect(ctx)
})
//动态用户连接管理
utility.SafeGo(func() {
manageBitgetUserConnections(ctx)
})
// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<-quit
fmt.Printf("%s Shutdown Server ... \r\n", pkg.GetCurrentTimeStr())
logger.Info("Server exiting")
return nil
}
func defaultInit(db *gorm.DB, ctx context.Context) {
//初始化 默认redis
helper.InitDefaultRedis(ext.ExtConfig.Redis.Addr, ext.ExtConfig.Redis.Password, ext.ExtConfig.Redis.Db)
helper.InitLockRedisConn(ext.ExtConfig.Redis.Addr, ext.ExtConfig.Redis.Password, strconv.Itoa(ext.ExtConfig.Redis.Db))
err := helper.DefaultRedis.Ping()
if err != nil {
logger.Error("初始化redis失败!请检查配置")
_, cancel := context.WithTimeout(context.Background(), 5*time.Second)
cancel()
} else {
logger.Info("redis初始化成功")
}
//初始化Bitget服务行情 + 用户私有)
logger.Info("=== 启动Bitget完整服务 ===")
// 启动Bitget行情服务
logger.Info("启动Bitget行情服务...")
if err := serverinit.BitgetMarketInit(); err != nil {
logger.Errorf("Bitget行情服务启动失败: %v", err)
}
// 初始化Bitget用户连接
logger.Info("启动Bitget用户服务...")
initBitgetUserConnections(db, ctx)
logger.Info("=== Bitget完整服务已启动 ===")
}
// 初始化Bitget用户连接
func initBitgetUserConnections(db *gorm.DB, ctx context.Context) {
var list []models.LineApiUser
err := db.Model(&models.LineApiUser{}).Where("open_status=1 AND exchange_type =?", global.EXCHANGE_BITGET).Find(&list).Error
if err != nil {
logger.Infof("获取Bitget用户api失败: %v", err)
return
}
logger.Infof("找到 %d 个Bitget用户开始建立连接...", len(list))
for _, item := range list {
// 遵循私有WebSocket密钥传递规范外部传入API密钥参数
createBitgetUserConnection(item)
}
}
// 创建Bitget用户连接遵循密钥传递规范
func createBitgetUserConnection(apiUser models.LineApiUser) {
logger.Infof("为Bitget用户 %d 建立私有连接", apiUser.Id)
// 现货WebSocket (wsType=0)
spotManager := bitgetservice.GetOrCreateBitgetWebSocketManager(
0, // 现货
apiUser.ApiKey,
apiUser.ApiSecret,
apiUser.Passphrase,
"", // proxyType - 从配置获取
"", // proxyAddress - 从配置获取
)
spotManager.Start()
// 合约WebSocket (wsType=1)
futuresManager := bitgetservice.GetOrCreateBitgetWebSocketManager(
1, // 合约
apiUser.ApiKey,
apiUser.ApiSecret,
apiUser.Passphrase,
"", // proxyType
"", // proxyAddress
)
futuresManager.Start()
logger.Infof("Bitget用户 %d 私有连接已建立", apiUser.Id)
}
// 动态Bitget用户连接管理
func manageBitgetUserConnections(ctx context.Context) {
ticker := time.NewTicker(time.Second * 5)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
logger.Info("Bitget用户连接管理器退出")
return
case <-ticker.C:
deleteKeys, _ := helper.DefaultRedis.GetAllList(rediskey.ApiUserDeleteList)
activeApis, _ := helper.DefaultRedis.GetAllList(rediskey.ApiUserActiveList)
//移除Bitget连接
for _, item := range deleteKeys {
logger.Infof("移除Bitget用户连接: %s", item)
// 停止现货WebSocket
bitgetservice.StopBitgetWebSocketManager(0, item)
// 停止合约WebSocket
bitgetservice.StopBitgetWebSocketManager(1, item)
if _, err := helper.DefaultRedis.LRem(rediskey.ApiUserDeleteList, item); err != nil {
logger.Errorf("移除待关闭websocket失败: %v", err)
}
}
//连接Bitget用户websocket
var apiUser models.LineApiUser
for _, item := range activeApis {
if item == "" {
continue
}
if err := sonic.Unmarshal([]byte(item), &apiUser); err != nil {
logger.Errorf("解析用户信息失败: %v", err)
continue
}
// 只处理Bitget用户
if apiUser.Id > 0 && apiUser.ExchangeType == global.EXCHANGE_BITGET {
logger.Info("为Bitget用户 %d 建立连接", apiUser.Id)
createBitgetUserConnection(apiUser)
if _, err := helper.DefaultRedis.LRem(rediskey.ApiUserActiveList, item); err != nil {
logger.Errorf("删除待触发的apiUser失败: %v", err)
}
}
}
}
}
}
// 定时清理日志
func clearLogJob(db *gorm.DB, ctx context.Context) {
ticker := time.NewTicker(time.Hour * 1)
defer ticker.Stop()
select {
case <-ctx.Done():
return
case <-ticker.C:
fileservice.ClearLogs(db)
}
}
// 定时重连websocket
func reconnect(ctx context.Context) error {
ticker := time.NewTicker(time.Hour * 1)
defer ticker.Stop()
select {
case <-ctx.Done():
return nil
case <-ticker.C:
// 这里可以添加Bitget连接的重连逻辑
// 类似于Binance的重连机制
logger.Info("检查Bitget连接状态...")
}
return nil
}