1、
Some checks failed
Build / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
build / Build (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitee (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitlab (push) Has been cancelled
Issue Close Require / issue-close-require (push) Has been cancelled
Issue Check Inactive / issue-check-inactive (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
build / Build (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitee (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitlab (push) Has been cancelled
Issue Close Require / issue-close-require (push) Has been cancelled
Issue Check Inactive / issue-check-inactive (push) Has been cancelled
This commit is contained in:
@ -159,3 +159,28 @@ func (e TmMember) GetMemberAdvent(c *gin.Context) {
|
|||||||
|
|
||||||
e.OK(datas, "success")
|
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")
|
||||||
|
}
|
||||||
|
|||||||
@ -38,5 +38,6 @@ func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
|
|||||||
r2.GET("member-advent", api.GetMemberAdvent) //获取用户即将过期的充值信息
|
r2.GET("member-advent", api.GetMemberAdvent) //获取用户即将过期的充值信息
|
||||||
|
|
||||||
r2.POST("recharge", rechargeApi.CreateOrder) //用户发起充值
|
r2.POST("recharge", rechargeApi.CreateOrder) //用户发起充值
|
||||||
|
r2.GET("order", rechargeApi.GetOrderInfo) //获取充值订单信息
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -242,3 +242,13 @@ type TmRechargeCallbackReq struct {
|
|||||||
ToAddress string `json:"to_address"`
|
ToAddress string `json:"to_address"`
|
||||||
TxHash string `json:"tx_hash"`
|
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"`
|
||||||
|
}
|
||||||
|
|||||||
@ -66,3 +66,11 @@ type TranslateUserInfoResp struct {
|
|||||||
UserApiKey string `json:"userApiKey" comment:"用户API Key"`
|
UserApiKey string `json:"userApiKey" comment:"用户API Key"`
|
||||||
RemainChars int `json:"remainChars" comment:"剩余可翻译字符数"`
|
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"`
|
||||||
|
}
|
||||||
|
|||||||
@ -33,6 +33,12 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq,
|
|||||||
return errors.New("查看对象不存在或无权查看")
|
return errors.New("查看对象不存在或无权查看")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = e.SyncPlatformAccount(entity)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TmPlatformAccount) SyncPlatformAccount(entity models.TmPlatformAccount) error {
|
||||||
platformService := TmPlatform{Service: e.Service}
|
platformService := TmPlatform{Service: e.Service}
|
||||||
|
|
||||||
platform, err := platformService.GetById(entity.PlatformId)
|
platform, err := platformService.GetById(entity.PlatformId)
|
||||||
@ -49,7 +55,7 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
config := TranslatorServiceConfig{
|
config := TranslatorServiceConfig{
|
||||||
DefaultProvider: "deepseek",
|
DefaultProvider: platform.Code,
|
||||||
ProviderConfigs: provider,
|
ProviderConfigs: provider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,49 +78,65 @@ func (e TmPlatformAccount) QueryRemain(req *dto.TmPlatformAccountQueryRemainReq,
|
|||||||
|
|
||||||
redishelper.DefaultRedis.SetString(key, strconv.Itoa(remainCount))
|
redishelper.DefaultRedis.SetString(key, strconv.Itoa(remainCount))
|
||||||
|
|
||||||
//如果为禁用则写入队列
|
// //如果为禁用则写入队列
|
||||||
if entity.Status == 2 {
|
// if entity.Status == 2 {
|
||||||
listKey := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, entity.PlatformKey)
|
// listKey := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, entity.PlatformKey)
|
||||||
vals, err := redishelper.DefaultRedis.GetAllList(listKey)
|
// vals, err := redishelper.DefaultRedis.GetAllList(listKey)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
e.Log.Errorf("获取redis列表失败 %v", err)
|
// e.Log.Errorf("获取redis列表失败 %v", err)
|
||||||
return errors.New("获取redis列表失败")
|
// return errors.New("获取redis列表失败")
|
||||||
}
|
// }
|
||||||
|
|
||||||
item := models.TmPlatformAccount{}
|
// item := models.TmPlatformAccount{}
|
||||||
hasData := false
|
// hasData := false
|
||||||
|
|
||||||
for _, val := range vals {
|
// for _, val := range vals {
|
||||||
sonic.UnmarshalString(val, &item)
|
// sonic.UnmarshalString(val, &item)
|
||||||
|
|
||||||
if item.ApiKey == entity.ApiKey {
|
// if item.ApiKey == entity.ApiKey {
|
||||||
hasData = true
|
// hasData = true
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !hasData {
|
// if !hasData {
|
||||||
entity.Status = 1
|
// entity.Status = 1
|
||||||
val, err := sonic.MarshalString(entity)
|
// val, err := sonic.MarshalString(entity)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
// err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
if err1 := redishelper.DefaultRedis.RPushList(listKey, val); err1 != nil {
|
// if err1 := redishelper.DefaultRedis.RPushList(listKey, val); err1 != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
if err1 := tx.Model(entity).Update("status", 1).Error; err1 != nil {
|
// if err1 := tx.Model(entity).Update("status", 1).Error; err1 != nil {
|
||||||
return err1
|
// return err1
|
||||||
}
|
// }
|
||||||
return nil
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,22 @@ type TmRechargeLog struct {
|
|||||||
service.Service
|
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 {
|
func (e TmRechargeLog) CleanExpiredOrder() error {
|
||||||
expireTime := time.Now().Add(5 * time.Minute)
|
expireTime := time.Now().Add(5 * time.Minute)
|
||||||
|
|||||||
@ -31,3 +31,32 @@ func TestDeepSeekTranslator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
fmt.Println(result)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
112
app/admin/service/translator_denosi.go
Normal file
112
app/admin/service/translator_denosi.go
Normal file
@ -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"
|
||||||
|
}
|
||||||
@ -6,15 +6,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/mq"
|
|
||||||
rediskey "go-admin/common/redis_key"
|
rediskey "go-admin/common/redis_key"
|
||||||
"go-admin/common/statuscode"
|
"go-admin/common/statuscode"
|
||||||
"go-admin/utils/redishelper"
|
"go-admin/utils/redishelper"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
commonDto "go-admin/common/dto"
|
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/bytedance/sonic"
|
||||||
"github.com/go-admin-team/go-admin-core/logger"
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"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")
|
logger.Error("failed to unmarshal config for Translator")
|
||||||
return nil, TransUnMarshalConfigErr
|
return nil, TransUnMarshalConfigErr
|
||||||
}
|
}
|
||||||
|
|
||||||
newAdapter = NewTransTranslator(&transCfg)
|
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:
|
default:
|
||||||
return nil, UnSportPlatformErr
|
return nil, UnSportPlatformErr
|
||||||
}
|
}
|
||||||
@ -237,18 +242,16 @@ func (s *TranslatorService) GetTranslator(platform string) (translator *Translat
|
|||||||
func (s *TranslatorService) GetNextAccount(platformCode string) (*models.TmPlatformAccount, error) {
|
func (s *TranslatorService) GetNextAccount(platformCode string) (*models.TmPlatformAccount, error) {
|
||||||
var val string
|
var val string
|
||||||
var err error
|
var err error
|
||||||
var remain int
|
// var remain int
|
||||||
key := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, platformCode)
|
key := fmt.Sprintf(rediskey.TM_PLATFORM_ACCOUNT_LIST_KEY, platformCode)
|
||||||
|
|
||||||
retries := []time.Duration{100 * time.Millisecond, 200 * time.Millisecond, 300 * time.Millisecond}
|
retries := []time.Duration{100 * time.Millisecond, 200 * time.Millisecond, 300 * time.Millisecond}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if val != "" {
|
if val != "" {
|
||||||
if remain > 0 {
|
// 放回队尾,继续轮询机制
|
||||||
// 放回队尾,继续轮询机制
|
if err := redishelper.DefaultRedis.RPushList(key, val); err != nil {
|
||||||
if err := redishelper.DefaultRedis.RPushList(key, val); err != nil {
|
s.Log.Errorf("failed to push account back to queue: %v", err)
|
||||||
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())
|
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{}
|
account := models.TmPlatformAccount{}
|
||||||
sonic.UnmarshalString(val, &account)
|
sonic.UnmarshalString(val, &account)
|
||||||
|
|
||||||
switch platformCode {
|
// switch platformCode {
|
||||||
case "deepseek":
|
// case "deepseek":
|
||||||
remain = 999999
|
// remain = 999999
|
||||||
default:
|
// default:
|
||||||
remain, _ = accountService.GetRemainCount(platformCode, account.ApiKey)
|
// remain, _ = accountService.GetRemainCount(platformCode, account.ApiKey)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
//取消限制
|
||||||
// 如果剩余字符数 <= 0,跳过该账号,不放回队列,并更新数据库状态
|
// 如果剩余字符数 <= 0,跳过该账号,不放回队列,并更新数据库状态
|
||||||
if remain <= 0 {
|
// if remain <= 0 {
|
||||||
event := commonDto.ExhaustedAccountMessage{
|
// event := commonDto.ExhaustedAccountMessage{
|
||||||
Id: account.Id,
|
// Id: account.Id,
|
||||||
Platform: platformCode,
|
// Platform: platformCode,
|
||||||
}
|
// }
|
||||||
payload, _ := sonic.Marshal(event)
|
// payload, _ := sonic.Marshal(event)
|
||||||
err = mq.MQ.Publish( // default exchange
|
// err = mq.MQ.Publish( // default exchange
|
||||||
"account_exhausted_queue",
|
// "account_exhausted_queue",
|
||||||
payload,
|
// payload,
|
||||||
)
|
// )
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
s.Log.Errorf("发送账号耗尽通知失败:%v", err)
|
// 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
|
return &account, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ func InitJob() {
|
|||||||
"RemainCharJob": RemainCharJob{},
|
"RemainCharJob": RemainCharJob{},
|
||||||
"CleanExpiredOrderJob": CleanExpiredOrderJob{},
|
"CleanExpiredOrderJob": CleanExpiredOrderJob{},
|
||||||
"TrxPaymentJob": TrxPaymentJob{},
|
"TrxPaymentJob": TrxPaymentJob{},
|
||||||
|
"SyncRemainCharJob": SyncRemainCharJob{},
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,12 @@ package jobs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
models2 "go-admin/app/jobs/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "github.com/go-admin-team/go-admin-core/logger"
|
log "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"
|
||||||
models2 "go-admin/app/jobs/models"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ func (e *ExecJob) Run() {
|
|||||||
//TODO: 待完善部分
|
//TODO: 待完善部分
|
||||||
//str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String()
|
//str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String()
|
||||||
//ws.SendAll(str)
|
//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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,18 @@ type RemainCharJob struct{}
|
|||||||
|
|
||||||
type CleanExpiredOrderJob 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 {
|
func (t CleanExpiredOrderJob) Exec(arg interface{}) error {
|
||||||
// expireTime := time.Now().Add(5 * time.Minute)
|
// expireTime := time.Now().Add(5 * time.Minute)
|
||||||
|
|||||||
@ -50,3 +50,23 @@ func TestClean(t *testing.T) {
|
|||||||
t.Error(err)
|
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")
|
||||||
|
}
|
||||||
|
|||||||
@ -5,9 +5,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go-admin/app/admin/service"
|
"go-admin/app/admin/service"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
|
rediskey "go-admin/common/redis_key"
|
||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
|
"go-admin/utils/redishelper"
|
||||||
"go-admin/utils/utility"
|
"go-admin/utils/utility"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -36,8 +38,22 @@ func (j TrxPaymentJob) Exec(arg interface{}) error {
|
|||||||
return nil
|
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 := service.TmRechargeLog{}
|
||||||
rechargeService.Orm = GetDb()
|
rechargeService.Orm = GetDb()
|
||||||
|
rechargeService.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
platforms, err := rechargeService.GetPlatforms()
|
platforms, err := rechargeService.GetPlatforms()
|
||||||
toAddresss := []string{}
|
toAddresss := []string{}
|
||||||
|
|
||||||
@ -67,6 +83,7 @@ func (j TrxPaymentJob) Exec(arg interface{}) error {
|
|||||||
|
|
||||||
for _, transfer := range transfers {
|
for _, transfer := range transfers {
|
||||||
if transfer.TransactionID == "" || transfer.ToAddress != toAddress {
|
if transfer.TransactionID == "" || transfer.ToAddress != toAddress {
|
||||||
|
logger.Infof("跳出插入 ", transfer)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,15 +96,20 @@ func (j TrxPaymentJob) Exec(arg interface{}) error {
|
|||||||
|
|
||||||
if utility.ContainsString(toAddresss, item.ToAddress) {
|
if utility.ContainsString(toAddresss, item.ToAddress) {
|
||||||
logs = append(logs, item)
|
logs = append(logs, item)
|
||||||
|
} else {
|
||||||
|
logger.Infof("没有写入logs ", item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(logs) > 0 {
|
if len(logs) > 0 {
|
||||||
|
|
||||||
err := rechargeService.PayCallBack(&logs)
|
err := rechargeService.PayCallBack(&logs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("执行完毕,err:", err.Error())
|
logger.Error("执行完毕,err:", err.Error())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// logger.Infof("接收地址:%s 合约地址:%s 无数据", toAddress, UsdtContractAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -96,19 +118,31 @@ func (j TrxPaymentJob) Exec(arg interface{}) error {
|
|||||||
// GetTRC20Transfers 获取指定 TRC20 代币的交易记录
|
// GetTRC20Transfers 获取指定 TRC20 代币的交易记录
|
||||||
func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, maxTimestamp int64) ([]dto.TRC20Transfer, error) {
|
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)
|
url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?contract_address=%s", config.ExtConfig.TrxGridUrl, accountAddress, contractAddress)
|
||||||
|
|
||||||
if minTimestamp > 0 {
|
if minTimestamp > 0 {
|
||||||
url += fmt.Sprintf("&min_timestamp=%d", minTimestamp)
|
url += fmt.Sprintf("&min_timestamp=%d", minTimestamp)
|
||||||
}
|
}
|
||||||
if maxTimestamp > 0 {
|
if maxTimestamp > 0 {
|
||||||
url += fmt.Sprintf("&max_timestamp=%d", maxTimestamp)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to send request: %v", err)
|
return nil, fmt.Errorf("failed to send request: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read response body: %v", err)
|
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 {
|
var result struct {
|
||||||
Data []dto.TRC20Transfer `json:"data"`
|
Data []dto.TRC20Transfer `json:"data"`
|
||||||
}
|
}
|
||||||
|
// logger.Info("查询结果:", string(body))
|
||||||
if err := json.Unmarshal(body, &result); err != nil {
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ type Extend struct {
|
|||||||
AMap AMap // 这里配置对应配置文件的结构即可
|
AMap AMap // 这里配置对应配置文件的结构即可
|
||||||
Mq MqConfig
|
Mq MqConfig
|
||||||
TrxGridUrl string `yaml:"trxGridUrl"`
|
TrxGridUrl string `yaml:"trxGridUrl"`
|
||||||
|
TronApiKey string `yaml:"tronApiKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AMap struct {
|
type AMap struct {
|
||||||
|
|||||||
@ -55,6 +55,7 @@ settings:
|
|||||||
pass: "123456"
|
pass: "123456"
|
||||||
#trx api
|
#trx api
|
||||||
trxGridUrl: "https://api.trongrid.io"
|
trxGridUrl: "https://api.trongrid.io"
|
||||||
|
tronApiKey: "223c129e-73f5-470f-9464-f9969846c134"
|
||||||
cache:
|
cache:
|
||||||
redis:
|
redis:
|
||||||
addr: 127.0.0.1:6379
|
addr: 127.0.0.1:6379
|
||||||
|
|||||||
44
utils/utility/safego.go
Normal file
44
utils/utility/safego.go
Normal file
@ -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) // 执行传入的函数
|
||||||
|
}()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user