From 9a954cedc0082af12e17b4ff5ad613d5a1b47cae Mon Sep 17 00:00:00 2001 From: hucan <951870319@qq.com> Date: Thu, 28 Aug 2025 11:43:11 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/tm_recharge_log.go | 25 ++++ app/admin/router/tm_member.go | 1 + app/admin/service/dto/tm_recharge_log.go | 10 ++ app/admin/service/dto/translate.go | 8 ++ app/admin/service/tm_platform_account.go | 92 ++++++++------ app/admin/service/tm_recharge_log.go | 16 +++ app/admin/service/translator_deepseek_test.go | 29 +++++ app/admin/service/translator_denosi.go | 112 ++++++++++++++++++ app/admin/service/translator_service.go | 68 ++++++----- app/jobs/examples.go | 1 + app/jobs/jobbase.go | 7 +- app/jobs/translate.go | 12 ++ app/jobs/translate_test.go | 20 ++++ app/jobs/trxpayment_job.go | 41 ++++++- config/extend.go | 1 + config/settings.yml | 1 + utils/utility/safego.go | 44 +++++++ 17 files changed, 415 insertions(+), 73 deletions(-) create mode 100644 app/admin/service/translator_denosi.go create mode 100644 utils/utility/safego.go diff --git a/app/admin/apis/tm_recharge_log.go b/app/admin/apis/tm_recharge_log.go index 1d598a8..307a672 100644 --- a/app/admin/apis/tm_recharge_log.go +++ b/app/admin/apis/tm_recharge_log.go @@ -159,3 +159,28 @@ func (e TmMember) GetMemberAdvent(c *gin.Context) { e.OK(datas, "success") } + +// 获取充值订单详情 +func (e *TmRechargeLog) GetOrderInfo(c *gin.Context) { + req := dto.TmRechargeLogGetOrderInfoReq{} + s := service.TmRechargeLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + + if err != nil { + e.Error(500, err, "") + return + } + + resp := dto.TmRechargeLogGetOrderInfoResp{} + err = s.GetOrderInfo(&req, &resp) + if err != nil { + e.Error(500, nil, err.Error()) + return + } + + e.OK(resp, "success") +} diff --git a/app/admin/router/tm_member.go b/app/admin/router/tm_member.go index 1a7558f..042e306 100644 --- a/app/admin/router/tm_member.go +++ b/app/admin/router/tm_member.go @@ -38,5 +38,6 @@ func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl r2.GET("member-advent", api.GetMemberAdvent) //获取用户即将过期的充值信息 r2.POST("recharge", rechargeApi.CreateOrder) //用户发起充值 + r2.GET("order", rechargeApi.GetOrderInfo) //获取充值订单信息 } } diff --git a/app/admin/service/dto/tm_recharge_log.go b/app/admin/service/dto/tm_recharge_log.go index 14a1d59..051032a 100644 --- a/app/admin/service/dto/tm_recharge_log.go +++ b/app/admin/service/dto/tm_recharge_log.go @@ -242,3 +242,13 @@ type TmRechargeCallbackReq struct { ToAddress string `json:"to_address"` TxHash string `json:"tx_hash"` } + +type TmRechargeLogGetOrderInfoReq struct { + OrderNo string `json:"orderNo" form:"orderNo" query:"orderNo" comment:"订单号"` +} + +type TmRechargeLogGetOrderInfoResp struct { + Id int `json:"id"` + OrderNo string `json:"orderNo"` + Status int `json:"status"` +} diff --git a/app/admin/service/dto/translate.go b/app/admin/service/dto/translate.go index a139a36..a7cbd95 100644 --- a/app/admin/service/dto/translate.go +++ b/app/admin/service/dto/translate.go @@ -66,3 +66,11 @@ type TranslateUserInfoResp struct { UserApiKey string `json:"userApiKey" comment:"用户API Key"` RemainChars int `json:"remainChars" comment:"剩余可翻译字符数"` } + +type DenosiTranslateRequest struct { + Model string `json:"model"` + Messages []Message `json:"messages"` + Temperature float64 `json:"temperature"` + MaxTokens int `json:"max_tokens"` + Stream bool `json:"stream"` +} diff --git a/app/admin/service/tm_platform_account.go b/app/admin/service/tm_platform_account.go index 1d74d0b..e62b9d4 100644 --- a/app/admin/service/tm_platform_account.go +++ b/app/admin/service/tm_platform_account.go @@ -33,6 +33,12 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq, return errors.New("查看对象不存在或无权查看") } + err = e.SyncPlatformAccount(entity) + + return err +} + +func (e *TmPlatformAccount) SyncPlatformAccount(entity models.TmPlatformAccount) error { platformService := TmPlatform{Service: e.Service} platform, err := platformService.GetById(entity.PlatformId) @@ -49,7 +55,7 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq, }, } config := TranslatorServiceConfig{ - DefaultProvider: "deepseek", + DefaultProvider: platform.Code, ProviderConfigs: provider, } @@ -72,49 +78,65 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq, redishelper.DefaultRedis.SetString(key, strconv.Itoa(remainCount)) - //如果为禁用则写入队列 - if entity.Status == 2 { - listKey := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, entity.PlatformKey) - vals, err := redishelper.DefaultRedis.GetAllList(listKey) + // //如果为禁用则写入队列 + // if entity.Status == 2 { + // listKey := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, entity.PlatformKey) + // vals, err := redishelper.DefaultRedis.GetAllList(listKey) - if err != nil { - e.Log.Errorf("获取redis列表失败 %v", err) - return errors.New("获取redis列表失败") - } + // if err != nil { + // e.Log.Errorf("获取redis列表失败 %v", err) + // return errors.New("获取redis列表失败") + // } - item := models.TmPlatformAccount{} - hasData := false + // item := models.TmPlatformAccount{} + // hasData := false - for _, val := range vals { - sonic.UnmarshalString(val, &item) + // for _, val := range vals { + // sonic.UnmarshalString(val, &item) - if item.ApiKey == entity.ApiKey { - hasData = true - break - } - } + // if item.ApiKey == entity.ApiKey { + // hasData = true + // break + // } + // } - if !hasData { - entity.Status = 1 - val, err := sonic.MarshalString(entity) + // if !hasData { + // entity.Status = 1 + // val, err := sonic.MarshalString(entity) - if err != nil { - return err - } + // if err != nil { + // return err + // } - err = e.Orm.Transaction(func(tx *gorm.DB) error { - if err1 := redishelper.DefaultRedis.RPushList(listKey, val); err1 != nil { - return err - } + // err = e.Orm.Transaction(func(tx *gorm.DB) error { + // if err1 := redishelper.DefaultRedis.RPushList(listKey, val); err1 != nil { + // return err + // } - if err1 := tx.Model(entity).Update("status", 1).Error; err1 != nil { - return err1 - } - return nil - }) + // if err1 := tx.Model(entity).Update("status", 1).Error; err1 != nil { + // return err1 + // } + // return nil + // }) - return nil - } + // return nil + // } + // } + } + return nil +} + +// 同步所有第三方账号余额 +func (e *TmPlatformAccount) SyncAll() error { + var datas []models.TmPlatformAccount + e.Orm.Model(&models.TmPlatformAccount{}).Where("status =1").Find(&datas) + platformService := TmPlatform{} + platformService.Orm = e.Orm + platformService.Log = e.Log + + for _, item := range datas { + if err := e.SyncPlatformAccount(item); err != nil { + e.Log.Errorf("同步平台账号余额 密钥:%s 失败 %v", item.ApiKey, err) } } diff --git a/app/admin/service/tm_recharge_log.go b/app/admin/service/tm_recharge_log.go index c1512fc..7952b11 100644 --- a/app/admin/service/tm_recharge_log.go +++ b/app/admin/service/tm_recharge_log.go @@ -30,6 +30,22 @@ type TmRechargeLog struct { service.Service } +func (e TmRechargeLog) GetOrderInfo(req *dto.TmRechargeLogGetOrderInfoReq, resp *dto.TmRechargeLogGetOrderInfoResp) error { + var data models.TmRechargeLog + if err := e.Orm.Model(&models.TmRechargeLog{}). + Where("order_no =?", req.OrderNo). + First(&data).Error; err != nil { + e.Log.Errorf("TmRechargeLogService GetOrderInfo error:%s \r\n", err) + return err + } + + resp.Id = data.Id + resp.OrderNo = data.OrderNo + resp.Status = data.Status + + return nil +} + // 清理过期订单 func (e TmRechargeLog) CleanExpiredOrder() error { expireTime := time.Now().Add(5 * time.Minute) diff --git a/app/admin/service/translator_deepseek_test.go b/app/admin/service/translator_deepseek_test.go index 3c8e839..b4527e3 100644 --- a/app/admin/service/translator_deepseek_test.go +++ b/app/admin/service/translator_deepseek_test.go @@ -31,3 +31,32 @@ func TestDeepSeekTranslator(t *testing.T) { } fmt.Println(result) } + +// 测试DeepSeekTranslator方法 +func TestDenosiTranslator(t *testing.T) { + config := TranslatorServiceConfig{ + DefaultProvider: "denosi", + ProviderConfigs: map[string]interface{}{ + "denosi": map[string]interface{}{ + "apiKey": "sk-PRXfCgLAefqo6jeYsJhKCU6hw5gmxkfNAOjISSQfOeHxqDw4", + "endpoint": "https://api.denosi.com/v1/chat/completions", + "model": "gpt-4o-mini", + }, + }, + } + + service, err := NewTranslatorService(&config) + + if err != nil { + fmt.Sprintln("报错:", err) + return + } + + result, err := service.providers["denosi"].Translate("成吉思汗", "zh", "fr") + + if err != nil { + fmt.Sprintln("报错:", err) + return + } + fmt.Println(result) +} diff --git a/app/admin/service/translator_denosi.go b/app/admin/service/translator_denosi.go new file mode 100644 index 0000000..4ccbca4 --- /dev/null +++ b/app/admin/service/translator_denosi.go @@ -0,0 +1,112 @@ +package service + +import ( + "bytes" + "encoding/json" + "fmt" + "go-admin/app/admin/service/dto" + "go-admin/utils/httphelper" + "io/ioutil" + "net/http" + "time" + + "github.com/bytedance/sonic" +) + +type DenosiTranslatorConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + Endpoint string `json:"endpoint"` + Model string `json:"model"` +} + +type DenosiTranslator struct { + config *DenosiTranslatorConfig + client *httphelper.HTTPClient +} + +// 初始化适配器实例 +func NewDenosiTranslator(config *DenosiTranslatorConfig) *DenosiTranslator { + defaultHeaders := map[string]string{ + "Content-Type": "application/json", + } + + httpClient := httphelper.NewHTTPClient( + 15*time.Second, + config.Endpoint, + defaultHeaders, + ) + + return &DenosiTranslator{ + config: config, + client: httpClient, + } +} + +// 翻译 +func (e *DenosiTranslator) Translate(text string, source string, target string) (*dto.TranslateResult, error) { + // TODO: 实现Deepseek API调用 + result := dto.TranslateResult{} + reqBody := dto.DenosiTranslateRequest{ + Model: e.config.Model, // v3 fast模型 + Stream: false, + Messages: []dto.Message{ + {Role: "system", Content: fmt.Sprintf("你是翻译专家,将内容从%s翻译为%s,仅返回翻译结果", source, target)}, + {Role: "user", Content: fmt.Sprintf("翻译:%s", text)}, + }, + Temperature: 0, + } + + data, err := sonic.Marshal(reqBody) + if err != nil { + return &result, err + } + + req, err := http.NewRequest("POST", e.config.Endpoint, bytes.NewBuffer(data)) + if err != nil { + return &result, err + } + + req.Header.Set("Authorization", "Bearer "+e.config.ApiKey) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + return &result, err + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + fmt.Println(string(body)) + if resp.StatusCode != 200 { + return &result, fmt.Errorf("Denosi error: %s", string(body)) + } + + var dsResp dto.DeepSeekResponse + err = json.Unmarshal(body, &dsResp) + if err != nil { + return &result, err + } + + if len(dsResp.Choices) == 0 { + return &result, fmt.Errorf("no translation result from Denosi") + } + + result.TranslatedText = dsResp.Choices[0].Message.Content + result.SourceLanguage = source + result.TargetLanguage = target + + return &result, nil +} + +func (e *DenosiTranslator) GetRemainCount() (int, error) { + // TODO: 实现Deepseek API调用 + + return 0, nil +} + +// 返回服务商 +func (e *DenosiTranslator) GetPlatform() string { + return "denosi" +} diff --git a/app/admin/service/translator_service.go b/app/admin/service/translator_service.go index 1296e13..403d4e0 100644 --- a/app/admin/service/translator_service.go +++ b/app/admin/service/translator_service.go @@ -6,15 +6,12 @@ import ( "fmt" "go-admin/app/admin/models" "go-admin/app/admin/service/dto" - "go-admin/common/mq" rediskey "go-admin/common/redis_key" "go-admin/common/statuscode" "go-admin/utils/redishelper" "time" "unicode/utf8" - commonDto "go-admin/common/dto" - "github.com/bytedance/sonic" "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" @@ -86,8 +83,16 @@ func NewTranslatorService(cfg *TranslatorServiceConfig) (*TranslatorService, err logger.Error("failed to unmarshal config for Translator") return nil, TransUnMarshalConfigErr } - newAdapter = NewTransTranslator(&transCfg) + case "denosi": + transCfgBytes, _ := json.Marshal(providerCfg) + var transCfg DenosiTranslatorConfig + if err := json.Unmarshal(transCfgBytes, &transCfg); err != nil { + logger.Error("failed to unmarshal config for Translator") + return nil, TransUnMarshalConfigErr + } + + newAdapter = NewDenosiTranslator(&transCfg) default: return nil, UnSportPlatformErr } @@ -237,18 +242,16 @@ func (s *TranslatorService) GetTranslator(platform string) (translator *Translat func (s *TranslatorService) GetNextAccount(platformCode string) (*models.TmPlatformAccount, error) { var val string var err error - var remain int + // var remain int key := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, platformCode) retries := []time.Duration{100 * time.Millisecond, 200 * time.Millisecond, 300 * time.Millisecond} defer func() { if val != "" { - if remain > 0 { - // 放回队尾,继续轮询机制 - if err := redishelper.DefaultRedis.RPushList(key, val); err != nil { - s.Log.Errorf("failed to push account back to queue: %v", err) - } + // 放回队尾,继续轮询机制 + if err := redishelper.DefaultRedis.RPushList(key, val); err != nil { + s.Log.Errorf("failed to push account back to queue: %v", err) } } }() @@ -269,35 +272,36 @@ func (s *TranslatorService) GetNextAccount(platformCode string) (*models.TmPlatf return nil, errors.New("failed to get account from queue after multiple retries: " + err.Error()) } - accountService := TmPlatformAccount{Service: s.Service} + // accountService := TmPlatformAccount{Service: s.Service} account := models.TmPlatformAccount{} sonic.UnmarshalString(val, &account) - switch platformCode { - case "deepseek": - remain = 999999 - default: - remain, _ = accountService.GetRemainCount(platformCode, account.ApiKey) - } + // switch platformCode { + // case "deepseek": + // remain = 999999 + // default: + // remain, _ = accountService.GetRemainCount(platformCode, account.ApiKey) + // } + //取消限制 // 如果剩余字符数 <= 0,跳过该账号,不放回队列,并更新数据库状态 - if remain <= 0 { - event := commonDto.ExhaustedAccountMessage{ - Id: account.Id, - Platform: platformCode, - } - payload, _ := sonic.Marshal(event) - err = mq.MQ.Publish( // default exchange - "account_exhausted_queue", - payload, - ) + // if remain <= 0 { + // event := commonDto.ExhaustedAccountMessage{ + // Id: account.Id, + // Platform: platformCode, + // } + // payload, _ := sonic.Marshal(event) + // err = mq.MQ.Publish( // default exchange + // "account_exhausted_queue", + // payload, + // ) - if err != nil { - s.Log.Errorf("发送账号耗尽通知失败:%v", err) - } + // if err != nil { + // s.Log.Errorf("发送账号耗尽通知失败:%v", err) + // } - return nil, errors.New("account exhausted and removed from queue") - } + // return nil, errors.New("account exhausted and removed from queue") + // } return &account, nil } diff --git a/app/jobs/examples.go b/app/jobs/examples.go index 6f2ec29..bd80a03 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -15,6 +15,7 @@ func InitJob() { "RemainCharJob": RemainCharJob{}, "CleanExpiredOrderJob": CleanExpiredOrderJob{}, "TrxPaymentJob": TrxPaymentJob{}, + "SyncRemainCharJob": SyncRemainCharJob{}, // ... } } diff --git a/app/jobs/jobbase.go b/app/jobs/jobbase.go index 5993b3c..337d0e1 100644 --- a/app/jobs/jobbase.go +++ b/app/jobs/jobbase.go @@ -2,11 +2,12 @@ package jobs import ( "fmt" + models2 "go-admin/app/jobs/models" + "time" + log "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk" - models2 "go-admin/app/jobs/models" "gorm.io/gorm" - "time" "github.com/robfig/cron/v3" @@ -59,7 +60,7 @@ func (e *ExecJob) Run() { //TODO: 待完善部分 //str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String() //ws.SendAll(str) - log.Info("[Job] JobCore %s exec success , spend :%v", e.Name, latencyTime) + log.Infof("[Job] JobCore %s exec success , spend :%v", e.Name, latencyTime) return } diff --git a/app/jobs/translate.go b/app/jobs/translate.go index c9e72f4..5c19c01 100644 --- a/app/jobs/translate.go +++ b/app/jobs/translate.go @@ -14,6 +14,18 @@ type RemainCharJob struct{} type CleanExpiredOrderJob struct{} +// 同步剩余字符 +type SyncRemainCharJob struct{} + +// 定时同步第三方用量 +func (t SyncRemainCharJob) Exec(arg interface{}) error { + platformAccountService := service.TmPlatformAccount{} + platformAccountService.Orm = GetDb() + platformAccountService.Log = logger.NewHelper(logger.DefaultLogger) + + return platformAccountService.SyncAll() +} + // 清理过期订单 func (t CleanExpiredOrderJob) Exec(arg interface{}) error { // expireTime := time.Now().Add(5 * time.Minute) diff --git a/app/jobs/translate_test.go b/app/jobs/translate_test.go index 61c32d4..3f9e00e 100644 --- a/app/jobs/translate_test.go +++ b/app/jobs/translate_test.go @@ -50,3 +50,23 @@ func TestClean(t *testing.T) { t.Error(err) } } + +func TestSyncPlatformAccountChar(t *testing.T) { + + initSetting() + + job := SyncRemainCharJob{} + + if err := job.Exec(nil); err != nil { + t.Error(err) + } +} + +func initSetting() { + dsn := "root:123456@tcp(127.0.0.1:3306)/aggregate_translate?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" + db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + sdk.Runtime.SetDb("default", db) + + redishelper.InitDefaultRedis("127.0.0.1:6379", "", 1) + redishelper.InitLockRedisConn("127.0.0.1:6379", "", "1") +} diff --git a/app/jobs/trxpayment_job.go b/app/jobs/trxpayment_job.go index 4800098..5310e22 100644 --- a/app/jobs/trxpayment_job.go +++ b/app/jobs/trxpayment_job.go @@ -5,9 +5,11 @@ import ( "fmt" "go-admin/app/admin/service" "go-admin/app/admin/service/dto" + rediskey "go-admin/common/redis_key" "go-admin/config" + "go-admin/utils/redishelper" "go-admin/utils/utility" - "io/ioutil" + "io" "net/http" "strings" "time" @@ -36,8 +38,22 @@ func (j TrxPaymentJob) Exec(arg interface{}) error { return nil } + key := fmt.Sprintf(rediskey.TM_RECHARGE_PRE_ORDER, "*") + keys, err := redishelper.DefaultRedis.ScanKeys(key) + + if err != nil { + logger.Error("查询redis key失败", err) + return nil + } + + if len(keys) == 0 { + logger.Info("没有待处理订单") + return nil + } + rechargeService := service.TmRechargeLog{} rechargeService.Orm = GetDb() + rechargeService.Log = logger.NewHelper(logger.DefaultLogger) platforms, err := rechargeService.GetPlatforms() toAddresss := []string{} @@ -67,6 +83,7 @@ func (j TrxPaymentJob) Exec(arg interface{}) error { for _, transfer := range transfers { if transfer.TransactionID == "" || transfer.ToAddress != toAddress { + logger.Infof("跳出插入 ", transfer) continue } @@ -79,15 +96,20 @@ func (j TrxPaymentJob) Exec(arg interface{}) error { if utility.ContainsString(toAddresss, item.ToAddress) { logs = append(logs, item) + } else { + logger.Infof("没有写入logs ", item) } } if len(logs) > 0 { + err := rechargeService.PayCallBack(&logs) if err != nil { logger.Error("执行完毕,err:", err.Error()) } + } else { + // logger.Infof("接收地址:%s 合约地址:%s 无数据", toAddress, UsdtContractAddress) } } return nil @@ -96,19 +118,31 @@ func (j TrxPaymentJob) Exec(arg interface{}) error { // GetTRC20Transfers 获取指定 TRC20 代币的交易记录 func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, maxTimestamp int64) ([]dto.TRC20Transfer, error) { url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?contract_address=%s", config.ExtConfig.TrxGridUrl, accountAddress, contractAddress) + if minTimestamp > 0 { url += fmt.Sprintf("&min_timestamp=%d", minTimestamp) } if maxTimestamp > 0 { url += fmt.Sprintf("&max_timestamp=%d", maxTimestamp) } - resp, err := http.Get(url) + // logger.Info("查询地址:", url) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %v", err) + } + + // 设置请求头(包含 TronGrid API Key) + req.Header.Set("Accept", "*/*") + req.Header.Set("TRON-PRO-API-KEY", config.ExtConfig.TronApiKey) // 从配置读取 API Key + + client := &http.Client{} + resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("failed to send request: %v", err) } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response body: %v", err) } @@ -116,6 +150,7 @@ func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, max var result struct { Data []dto.TRC20Transfer `json:"data"` } + // logger.Info("查询结果:", string(body)) if err := json.Unmarshal(body, &result); err != nil { return nil, fmt.Errorf("failed to unmarshal response: %v", err) } diff --git a/config/extend.go b/config/extend.go index 0117474..7703662 100644 --- a/config/extend.go +++ b/config/extend.go @@ -13,6 +13,7 @@ type Extend struct { AMap AMap // 这里配置对应配置文件的结构即可 Mq MqConfig TrxGridUrl string `yaml:"trxGridUrl"` + TronApiKey string `yaml:"tronApiKey"` } type AMap struct { diff --git a/config/settings.yml b/config/settings.yml index 36fb5e7..ff14eae 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -55,6 +55,7 @@ settings: pass: "123456" #trx api trxGridUrl: "https://api.trongrid.io" + tronApiKey: "223c129e-73f5-470f-9464-f9969846c134" cache: redis: addr: 127.0.0.1:6379 diff --git a/utils/utility/safego.go b/utils/utility/safego.go new file mode 100644 index 0000000..ddf7a1b --- /dev/null +++ b/utils/utility/safego.go @@ -0,0 +1,44 @@ +package utility + +import ( + "fmt" + "runtime" + "runtime/debug" + "strings" + + "github.com/go-admin-team/go-admin-core/logger" +) + +// SafeGo 安全地启动一个 goroutine,捕获 panic +func SafeGo(fn func()) { + go func() { + defer func() { + if r := recover(); r != nil { + // 记录 Goroutine ID、panic 信息和堆栈 + logger.Error(fmt.Sprintf("Recovered from panic in Goroutine %s: %v\nStack Trace:\n%s", GetGoroutineID(), r, string(debug.Stack()))) + } + }() + fn() + }() +} + +// 获取 Goroutine ID +func GetGoroutineID() string { + buf := make([]byte, 64) + n := runtime.Stack(buf, false) + stack := string(buf[:n]) + // 提取 Goroutine ID + id := strings.Split(stack, " ")[1] + return id +} + +func SafeGoParam[T any](fn func(T), param T) { + go func() { + defer func() { + if r := recover(); r != nil { + logger.Error(fmt.Sprintf(" SafeGoParam Recovered from panic in Goroutine %s: %v\nStack Trace:\n%s", GetGoroutineID(), r, string(debug.Stack()))) + } + }() + fn(param) // 执行传入的函数 + }() +}