diff --git a/app/admin/models/sms_renewal_log.go b/app/admin/models/sms_renewal_log.go index b2de4d6..31efa1a 100644 --- a/app/admin/models/sms_renewal_log.go +++ b/app/admin/models/sms_renewal_log.go @@ -29,6 +29,7 @@ type SmsRenewalLog struct { ApiKey string `json:"apiKey" gorm:"->"` BillingCycleId string `json:"billingCycleId" gorm:"->"` ActivationId string `json:"activationId" gorm:"->"` + PlatformState string `json:"platformState" gorm:"-"` models.ModelTime models.ControlBy } diff --git a/app/admin/service/dto/sms_renewal_log.go b/app/admin/service/dto/sms_renewal_log.go index 578985f..6fc16f0 100644 --- a/app/admin/service/dto/sms_renewal_log.go +++ b/app/admin/service/dto/sms_renewal_log.go @@ -138,12 +138,13 @@ type ManualDeductReq struct { } type ManualDeductResp struct { - ActivationId string `json:"activationId" comment:"激活id"` - TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"` - PayOrderNo string `json:"payOrderNo" comment:"支付订单号"` - BeginTime time.Time `json:"beginTime" comment:"开始时间"` - EndTime *time.Time `json:"endTime" comment:"结束时间"` - Status int `json:"status" comment:"状态 1-预扣费 2-成功 3-失败"` + ActivationId string `json:"activationId" comment:"激活id"` + TradeOrderNo string `json:"tradeOrderNo" comment:"交易订单号"` + PayOrderNo string `json:"payOrderNo" comment:"支付订单号"` + BeginTime time.Time `json:"beginTime" comment:"开始时间"` + EndTime *time.Time `json:"endTime" comment:"结束时间"` + Status int `json:"status" comment:"状态 1-预扣费 2-成功 3-失败"` + PlatformState string `json:"platformState" comment:"平台状态 verificationPending┃verificationCompleted┃verificationCanceled┃verificationTimedOut┃verificationReported┃verificationRefunded┃verificationReused┃verificationReactivated┃renewableActive┃renewableOverdue┃renewableExpired┃renewableRefunded┃nonrenewableActive┃nonrenewableExpired┃nonrenewableRefunded"` } // 续费详情 diff --git a/app/admin/service/sms_phone.go b/app/admin/service/sms_phone.go index e0cac44..c0ba532 100644 --- a/app/admin/service/sms_phone.go +++ b/app/admin/service/sms_phone.go @@ -1,10 +1,12 @@ package service import ( + "database/sql" "errors" "fmt" "net/http" "strconv" + "sync" "time" "github.com/go-admin-team/go-admin-core/sdk/service" @@ -712,9 +714,10 @@ func (e *SmsPhone) ChangeAutoRenewManage(platform, apiKey string, activationId s return service.ChangeAutoRenewForApi(activationId, status, &apiInfo) case global.SmsPlatformTextVerified: - service := SmsTextVerified{Service: e.Service} + // service := SmsTextVerified{Service: e.Service} - return service.Renew(activationId, status, &apiInfo) + // return service.Renew(activationId, status, &apiInfo) + return statuscode.Success default: return statuscode.SmsPlatformUnavailable } @@ -919,3 +922,116 @@ func (e *SmsPhone) syncLoop(nextUrl string, textVerifiedService SmsTextVerified, } return rentalList, nil } +func (e *SmsPhone) GetPhoneActualEnd() error { + var phones []models.SmsPhone + + // 查询待处理的号码 + if err := e.Orm.Model(&models.SmsPhone{}). + Joins("LEFT JOIN sms_phone_judge AS s ON sms_phone.id = s.phone_id"). + Where("sms_phone.platform_code = ? AND sms_phone.expire_time > ? AND s.id IS NULL", + global.SmsPlatformTextVerified, "2025-11-17"). + Select("sms_phone.*"). + Find(&phones).Error; err != nil { + e.Log.Errorf("查询手机号码失败 err:%v", err) + return err + } + + if len(phones) == 0 { + return nil + } + workerCount := 4 // 开 8 个并发 worker + e.runWorkerPool(phones, workerCount) + return nil +} + +func (e *SmsPhone) runWorkerPool(phones []models.SmsPhone, workerCount int) { + phoneChan := make(chan models.SmsPhone, workerCount*2) + var wg sync.WaitGroup + wg.Add(workerCount) + + // 开 worker + for i := 0; i < workerCount; i++ { + go func() { + defer wg.Done() + e.workerProcess(phoneChan) + }() + } + + // 投递任务 + for _, p := range phones { + phoneChan <- p + } + close(phoneChan) + + // 等待全部 worker 完成 + wg.Wait() +} +func (e *SmsPhone) workerProcess(ch <-chan models.SmsPhone) { + service := SmsTextVerified{Service: e.Service} + smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log) + + for item := range ch { + + // 获取 API info + apiInfo, err := smsPlatformKeyRedis.GetApiInfo(item.PlatformCode, item.ApiKey) + if err != nil { + e.Log.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", item.PlatformCode, err) + continue + } + + // 获取账单周期 + cycleInfo, err := service.GetBillingCycle(item.BillingCycleId, &apiInfo) + if err != nil { + e.Log.Errorf("获取账单周期失败 [Phone: %s]: %v", item.Phone, err) + continue + } + + // 插入判断表 + if err := e.Orm.Exec(` + INSERT INTO sms_phone_judge(phone_id, phone, expire_time, end_time) + VALUES(@phone_id, @phone, @expire_time, @endTime) + `, + sql.Named("phone_id", item.Id), + sql.Named("phone", item.Phone), + sql.Named("expire_time", item.ExpireTime), + sql.Named("endTime", cycleInfo.RenewedThrough), + ).Error; err != nil { + + e.Log.Errorf("插入 sms_phone_judge 失败 [Phone: %s]: %v", item.Phone, err) + continue + } + } +} + +// 设置为平台手动续费 +func (e *SmsPhone) SetManualRenewal() error { + var phones []models.SmsPhone + if err := e.Orm.Model(&models.SmsPhone{}). + Where("platform_auto =1 and auto_renewal = 1 and platform_code = ?", global.SmsPlatformTextVerified). + Find(&phones).Error; err != nil { + e.Log.Errorf("查询手机号码失败 err:%v", err) + return err + } + smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log) + for _, item := range phones { + apiInfo, err := smsPlatformKeyRedis.GetApiInfo(item.PlatformCode, item.ApiKey) + if err != nil { + e.Log.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", item.PlatformCode, err) + continue + } + service := SmsTextVerified{Service: e.Service} + if err := service.Renew(item.ActivationId, false, &apiInfo); err != statuscode.Success { + e.Log.Errorf("设置为平台手动续费失败 [ActivationId: %s]: %v", item.ActivationId, err) + continue + } + + if err := e.Orm.Model(&item). + Where("activation_id = ?", item.ActivationId). + Update("platform_auto", 2).Error; err != nil { + e.Log.Errorf("更新手动续费id失败 err:%v", err) + continue + } + } + + return nil +} diff --git a/app/admin/service/sms_phone_test.go b/app/admin/service/sms_phone_test.go index 96c51d4..7e88ba2 100644 --- a/app/admin/service/sms_phone_test.go +++ b/app/admin/service/sms_phone_test.go @@ -83,7 +83,7 @@ func TestManualRenewal(t *testing.T) { service := SmsRenewalLog{} service.Orm = db service.Log = logger.NewHelper(logger.DefaultLogger) - activationId := "lr_01K5DP71G06SFX84S7W99D61F9" + activationId := "lr_01KA8J2AKDN480QE5HGTQGEXEW" if _, err := service.ManualDeduct(&dto.ManualDeductReq{ ActivationId: activationId, @@ -92,3 +92,32 @@ func TestManualRenewal(t *testing.T) { t.Error(err) } } + +func TestGetPhoneActualEnd(t *testing.T) { + db := initSetting() + + service := SmsPhone{} + service.Orm = db + service.Log = logger.NewHelper(logger.DefaultLogger) + + // if err := service.Orm.Exec("truncate table sms_phone_judge").Error; err != nil { + // t.Error(err) + // } + + if err := service.GetPhoneActualEnd(); err != nil { + t.Error(err) + } +} + +// 测试修改为手动续期 +func TestSetManualRenewal(t *testing.T) { + db := initSetting() + + service := SmsPhone{} + service.Orm = db + service.Log = logger.NewHelper(logger.DefaultLogger) + + if err := service.SetManualRenewal(); err != nil { + t.Fatalf("SetManualRenewal failed: %v", err) + } +} diff --git a/app/admin/service/sms_receive_log_test.go b/app/admin/service/sms_receive_log_test.go index afa9417..b567146 100644 --- a/app/admin/service/sms_receive_log_test.go +++ b/app/admin/service/sms_receive_log_test.go @@ -14,7 +14,7 @@ import ( ) func initSetting() *gorm.DB { - dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server_prod?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" + dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms" db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) sdk.Runtime.SetDb("default", db) // config.ExtConfig. diff --git a/app/admin/service/sms_renewal_log.go b/app/admin/service/sms_renewal_log.go index 90f4a6d..bc3ea2a 100644 --- a/app/admin/service/sms_renewal_log.go +++ b/app/admin/service/sms_renewal_log.go @@ -182,6 +182,7 @@ func (e *SmsRenewalLog) ManualDeduct(req *dto.ManualDeductReq, userId int) (dto. result.PayOrderNo = renewLog.PayOrderNo result.BeginTime = req.BeginTime result.EndTime = renewLog.TargetTime + result.PlatformState = renewLog.PlatformState } return result, statuscode.Success @@ -391,18 +392,20 @@ func (e *SmsPhone) getRenewalConfigs() (map[string]models.SmsServices, map[strin func (e *SmsRenewalLog) processPhoneRenewal(phone models.SmsPhone, serviceMap map[string]models.SmsServices, premiumMap map[string]dto.GetSysConfigByKEYForServiceResp, tradeOrderNo string, admin bool) (models.SmsRenewalLog, error) { var renewLog models.SmsRenewalLog + var platformState string smsPlatformKeyRedis := NewSmsPlatformKeyRedis(e.Orm, e.Log) apiInfo, err := smsPlatformKeyRedis.GetApiInfo(phone.PlatformCode, phone.ApiKey) if err != nil { return renewLog, fmt.Errorf("获取短信平台密钥失败 [PlatformCode: %s]: %v", phone.PlatformCode, err) } - //续期id为空 重新获取 - if phone.BillingCycleId == "" { - switch phone.PlatformCode { - case global.SmsPlatformTextVerified: + switch phone.PlatformCode { + case global.SmsPlatformTextVerified: + textVerifiedService := SmsTextVerified{Service: e.Service} + + //续期id为空 重新获取 + if phone.BillingCycleId == "" { //可以手动续费 - textVerifiedService := SmsTextVerified{Service: e.Service} detail, code := textVerifiedService.GetRentalDetail(phone.ActivationId, &apiInfo) if code != statuscode.Success { @@ -411,9 +414,57 @@ func (e *SmsRenewalLog) processPhoneRenewal(phone models.SmsPhone, serviceMap ma } phone.BillingCycleId = detail.BillingCycleId - case global.SmsPlatformDaisysms: - //只有自动续费的 用定时服务查询状态 + platformState = detail.State + } else { + var billingCycle dto.VerificationRentalDetailResp + + if err := utility.Retry(4, time.Millisecond*150, func() error { + var newErr int + billingCycle, newErr = textVerifiedService.GetRentalDetail(phone.ActivationId, &apiInfo) + + if newErr != statuscode.Success { + return fmt.Errorf("错误code:%d", newErr) + } else { + return nil + } + }); err != nil { + logger.Errorf("获取短信验证码续费详情失败 [BillingCycleID: %s]: %v", phone.BillingCycleId, err) + return renewLog, fmt.Errorf("获取短信验证码续费详情失败 [BillingCycleID: %s]: %v", phone.BillingCycleId, err) + } + + renewLog.ActivationId = billingCycle.ID + platformState = billingCycle.State } + + case global.SmsPlatformDaisysms: + //只有自动续费的 用定时服务查询状态 + } + + // 已取消、已过期、已逾期 都视为续费失败 + if platformState == "renewableRefunded" || + platformState == "renewableExpired" || + platformState == "renewableOverdue" { + var remark string + if platformState == "renewableRefunded" { + remark = "已取消" + } else if platformState == "renewableExpired" { + remark = "已过期" + } else if platformState == "renewableOverdue" { + remark = "已逾期" + } + + if err := e.Orm.Model(&phone).Where("id =?", phone.Id). + Updates(map[string]interface{}{ + "auto_renewal": 2, + "remark": remark, + }).Error; err != nil { + logger.Errorf("更新短信验证码续费状态失败 [PhoneID: %d]: %v", phone.Id, err) + } else { + logger.Errorf("短信验证码续费状态为 %s,续费失败", platformState) + } + + renewLog.PlatformState = platformState + return renewLog, nil } // 获取服务价格 @@ -430,6 +481,7 @@ func (e *SmsRenewalLog) processPhoneRenewal(phone models.SmsPhone, serviceMap ma // 创建续费日志 renewLog = e.createRenewalLog(phone, renewalPrice, tradeOrderNo) + renewLog.PlatformState = platformState // 执行续费事务 if err := e.executeRenewalTransaction(phone, renewalPrice, &renewLog, &apiInfo, admin); err != nil { @@ -526,6 +578,13 @@ func (e *SmsRenewalLog) executeRenewalTransaction(phone models.SmsPhone, price d if code == statuscode.NothingToRenew { if renewCode := textVerifiedService.Renew(phone.ActivationId, true, apiInfo); renewCode == statuscode.Success { code = textVerifiedService.ManualRenewal(phone.BillingCycleId, apiInfo) + + if code == statuscode.Success { + //再取消自动续费 + if renewCode := textVerifiedService.Renew(phone.ActivationId, false, apiInfo); renewCode != statuscode.Success { + logger.Errorf("取消自动续费失败 [ActivationID: %s]: %v", phone.ActivationId, renewCode) + } + } } } diff --git a/app/admin/service/sms_text_verified.go b/app/admin/service/sms_text_verified.go index 3d9f984..0172d03 100644 --- a/app/admin/service/sms_text_verified.go +++ b/app/admin/service/sms_text_verified.go @@ -403,6 +403,7 @@ func (e *SmsTextVerified) GetNumberAndWakeUp(tye int, serviceCode string, price // period 时长(月=30天) func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price decimal.Decimal, period int, apiInfo *dto.SmsPlatformKeyQueueDto) (dto.SmsPhoneGetPhoneResp, int) { //这个平台的所有号码都是美国号码 默认国家代码都是 +1 + var bytes []byte var err error var createResp dto.TextVerifiedResp var result dto.SmsPhoneGetPhoneResp @@ -412,7 +413,7 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec createResp, code = e.CreateVerification(serviceCode, apiInfo) if code == statuscode.Success && createResp.Href != "" { - bytes, err := e.doRequest(&createResp, apiInfo) + bytes, err = e.doRequest(&createResp, apiInfo) if err != nil { e.Log.Errorf("短效号码 获取号码失败:%v", e) @@ -421,7 +422,7 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec resp := dto.VerificationDTO{} - if err := sonic.Unmarshal(bytes, &resp); err != nil { + if err = sonic.Unmarshal(bytes, &resp); err != nil { e.Log.Errorf("短效号码 获取号码失败:%v", e) return result, 0 } @@ -443,15 +444,28 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec if err == nil && createResp.Href != "" { saleId := getIdByUrl(createResp.Href) - bytes, err := e.doRequest(&createResp, apiInfo) - if err != nil { + if err = utility.Retry(6, time.Millisecond*150, func() error { + newBytes, newErr := e.doRequest(&createResp, apiInfo) + + if newErr != nil { + return fmt.Errorf("获取长效号码失败:%v", newErr) + } + + bytes = newBytes + + return nil + }); err != nil { e.Log.Errorf("通过销售id [%s] 获取号码失败:%v", saleId, err) + } + + if len(bytes) == 0 { + e.Log.Errorf("获取长效号码失败,没有返回值") return result, statuscode.ServerError } resp := dto.SaleResponse{} - if err := sonic.Unmarshal(bytes, &resp); err != nil { + if err = sonic.Unmarshal(bytes, &resp); err != nil { e.Log.Errorf("反序列化失败:%v", err) return result, statuscode.ServerError @@ -461,7 +475,7 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec for _, v := range resp.Reservations { if v.ID != "" { result.Id = v.ID - continue + break } } @@ -470,20 +484,36 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec return result, statuscode.ServerError } - detail, code := e.GetRentalDetail(result.Id, apiInfo) + var detail dto.VerificationRentalDetailResp - if code != statuscode.Success { - return result, code + //带重试的获取详情 + if err = utility.Retry(6, time.Millisecond*150, func() error { + dDetail, dCode := e.GetRentalDetail(result.Id, apiInfo) + + if dCode != statuscode.Success { + return fmt.Errorf("code :%d", dCode) + } + + detail = dDetail + + return nil + }); err != nil { + e.Log.Errorf("获取长效号码失败:%v", err) + return result, statuscode.ServerError } - result.Phone = "1" + detail.Number - result.BillingCycleId = detail.BillingCycleId - endTime := resp.UpdatedAt.AddDate(0, 0, 30) - result.EndAt = &(endTime) // 30天后过期 + if detail.ID == "" { + e.Log.Errorf("获取长效号码失败,没有返回值") + return result, statuscode.ServerError + } else { + result.Phone = "1" + detail.Number + result.BillingCycleId = detail.BillingCycleId + endTime := resp.UpdatedAt.AddDate(0, 0, 30) + result.EndAt = &(endTime) // 30天后过期 + } return result, statuscode.Success } - } else if err == nil && createResp.Href == "" { e.Log.Errorf("获取长效号码失败,没有返回值") return result, statuscode.ServerError @@ -499,10 +529,6 @@ func (e *SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price dec return result, statuscode.SmsPlatformUnavailable } - if err != nil { - return result, statuscode.ServerError - } - return result, statuscode.Success } diff --git a/app/admin/service/sms_text_verified_test.go b/app/admin/service/sms_text_verified_test.go index ac5d98f..7b8eda4 100644 --- a/app/admin/service/sms_text_verified_test.go +++ b/app/admin/service/sms_text_verified_test.go @@ -2,6 +2,7 @@ package service import ( "go-admin/common/global" + "go-admin/common/statuscode" "testing" "github.com/go-admin-team/go-admin-core/logger" @@ -82,3 +83,100 @@ func TestInitSmsLogs(t *testing.T) { t.Log("InitSmsLogs succeeded") } } + +func TestGetRentalDetail(t *testing.T) { + db := initSetting() + + s := SmsTextVerified{} + s.Orm = db + s.Log = logger.NewHelper(logger.DefaultLogger) + ids := []string{ + "lr_01K5YP0KD77813BGHEVNBHFSV4", + "lr_01K7SKT1X3DM8VW4C131KFJKKP", + "lr_01K7SRS4JZEWK7K479YG74WSMW", + "lr_01K7SSPHC13ZY6DPD8M3X2M47H", + "lr_01K7SV8DP7DMBVTH599DA3AE61", + "lr_01K7W84KPA3M31KWZ06GXE1YGN", + "lr_01K7W8VXEA15GBPXNWQ7EP3MTN", + "lr_01K7WBYG9G25VAX7GJQHG8AXV2", + "lr_01K7X5ZGRE9YMWGPTA9EEXNY6F", + "lr_01K7YG5FVJM03WPRNA8R1RYDHQ", + "lr_01K81MR0DJXF4QAQKR03APT1MR", + "lr_01K81Q1BZ05EW7VECPB4016CJH", + "lr_01K81YRE55T41J8CNT8SYPVRQB", + "lr_01K849VP722Q67CTS69WNPF3CV", + "lr_01K849W7N74ATK14DFBGPRPFT5", + "lr_01K86KYAPFRM776K9H63HC142M", + "lr_01K5YP0KD77813BGHEVNBHFSV4", + "lr_01K88R5F04HXDM3T7TA6Y101FV", + "lr_01K88S2SQ9R0AKM37NX6N9Q3K4", + "lr_01K88S3XBP3VWTBCQ51R1NPPXM", + "lr_01K88SG5FGYCQSH2K0CDRGGXJV", + "lr_01K88SR36PQ20SDCAZT45HZXH6", + "lr_01K88SVWPP1AQDYG8MJNEG12WQ", + "lr_01K8BM8W13TF487G1QR0N3DPXQ", + "lr_01K8BQV5V7HD38NBBMYNQ46ATE", + "lr_01K8BR1TAMPNJ2NZ8A5YN4XRP7", + "lr_01K8BRB8TX1NTQ8F99Q8VJEWQY", + "lr_01K8BSNK4PB5DT4E5BRQP9FT89", + "lr_01K8BT9W2HGVJHB09WN5Q8ZAFW", + "lr_01K8CKGF1SBPJNHQR11Q8TKG34", + "lr_01K8CMMW8EGHD8GZTYARMZ15YC", + "lr_01K8E4CVMPMVF61NZ7J0PN92VF", + "lr_01K8E6Z10C463TMGZ5WNQE151B", + "lr_01K8EJAH4BKTAF6DGSEHWB658S", + "lr_01K8EJGRHVJBTCR4FT5QVD01BK", + "lr_01K8EPKWZDAW6C9BFKXZJ9ZXXS", + "lr_01K8EPMNRY3DKAWNT5AHCQV5FP", + "lr_01K8KZMPDE39S2AKKKY215PPQC", + "lr_01K8MAPDCNMR2WVR8QKQ1DBN8Z", + "lr_01K8RBQJYEGS28AMW57PTKD2RQ", + "lr_01K8RPCC5GAQ6YD5WK8P0FVEN6", + "lr_01K8RR7F4H4RRZE5TSES6RXD08", + "lr_01K8RRQ7WBTY4AC4Q1WP1KAFNN", + "lr_01K8S5F3HPHTXV17W68P4M5CK0", + "lr_01K8S5G5JV9A69WH4SNM79AEYJ", + "lr_01K907JVTN6C9QC17AN97RM8TC", + "lr_01K907Z508W78B2PYZZ8E3PWJX", + "lr_01K909WET271Z8JEYRKGEJJBXG", + "lr_01K90C2V8RQ06914J6VBEV9MV6", + "lr_01K90G3WCFB8RS8SWNS73KW189", + "lr_01K90PJTX2GRXZMTZ1ZTN7SEEB", + "lr_01K92FTF3WJRC3YVYEK62Y0PV2", + "lr_01K95G9WHTX8ASMT1N6RVJAW0Z", + "lr_01K95GK2762Z6V9WFM43VVMRE8", + "lr_01K98WR5PGNYVDYWYK8RMHXM1D", + "lr_01K9ANC9ANW2TM54J4EM9TM7H0", + "lr_01K9AW71BGJAV6VQP7REC023K4", + "lr_01K9B0MA8A7E3KD75DA2JQZ8MA", + "lr_01K9B0YX9MBB22XY7NAQHJ6W68", + "lr_01K9DABMP1XJP82HHE114B0C5H", + "lr_01K9DCY25FRM0V85XRW7QJ5MVQ", + "lr_01K9QJD4RQ5DK95WV55PVMWYRK", + "lr_01K9SQVZ0QBXAT4MKZG0ZFV8NQ", + "lr_01K9TQ9GYP29X2Q7YPN5BH79ZY", + "lr_01K9X7ABQZ1QGVXYXMY00PNP4F", + "lr_01K9Z50GG4E50CV6X7HFF6H671", + "lr_01K9Z5GZEF8Q5Z3TWMFMKT8ME1", + "lr_01K9ZBADB7AASXZF0FARN94FAN", + "lr_01K9ZBPTVAER3EHC20YJ3BWJBB", + "lr_01K9ZC5V6E29R2W798FJTCHQZG", + } + + smsPlatformKeyRedis := NewSmsPlatformKeyRedis(s.Orm, s.Log) + apiInfo, err := smsPlatformKeyRedis.GetApiInfo(global.SmsPlatformTextVerified, "ZQ0swXnsaPpeGdwa3c7gT9U9I1Oh9WoDHx0amuYovvaHuqd5u6B4NBBUSUBjR") + + if err != nil { + s.Log.Errorf("获取API信息失败: %v", err) + t.Error("获取API信息失败", err) + } + + for _, item := range ids { + rentalDetail, errCode := s.GetRentalDetail(item, &apiInfo) + if errCode != statuscode.Success { + t.Errorf("GetRentalDetail failed: %v", errCode) + } else { + t.Logf("activationId:%s 状态:%s", rentalDetail.ID, rentalDetail.State) + } + } +} diff --git a/app/jobs/examples.go b/app/jobs/examples.go index ecf58eb..89de4f8 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -10,16 +10,17 @@ import ( // 字典 key 可以配置到 自动任务 调用目标 中; func InitJob() { jobList = map[string]JobExec{ - "ExamplesOne": ExamplesOne{}, - "TrxPaymentJob": TrxPaymentJob{}, - "CliProxyTrafficsJob": CliProxyJob{}, - "RenewalJob": RenewalJob{}, //长效ip定时续期 - "ExpireProxyJob": ExpireProxyJob{}, //定时过期代理 - "CleanExpiredOrderJob": CleanExpiredOrderJob{}, //清理过期订单 - "SmsJob": SmsJob{}, //短信定时查询验证码 - "SmsRenewalJob": SmsRenewalJob{}, //短信定时自动续期 - "AutoDeleteJob": AutoDeleteJob{}, //定时删除任务 - "SmsPriceJob": SmsPriceJob{}, // 短信价格定时同步 + "ExamplesOne": ExamplesOne{}, + "TrxPaymentJob": TrxPaymentJob{}, + "CliProxyTrafficsJob": CliProxyJob{}, + "RenewalJob": RenewalJob{}, //长效ip定时续期 + "ExpireProxyJob": ExpireProxyJob{}, //定时过期代理 + "CleanExpiredOrderJob": CleanExpiredOrderJob{}, //清理过期订单 + "SmsJob": SmsJob{}, //短信定时查询验证码 + "SmsRenewalJob": SmsRenewalJob{}, //短信定时自动续期 + "AutoDeleteJob": AutoDeleteJob{}, //定时删除任务 + "SmsPriceJob": SmsPriceJob{}, // 短信价格定时同步 + "SmsCancelPlatformAuto": SmsCancelPlatformAuto{}, // 短信定时取消自动续期 // ... } } diff --git a/app/jobs/sms_job.go b/app/jobs/sms_job.go index 0f46c93..79cd6d4 100644 --- a/app/jobs/sms_job.go +++ b/app/jobs/sms_job.go @@ -8,6 +8,7 @@ import ( type SmsJob struct{} type SmsPriceJob struct{} +type SmsCancelPlatformAuto struct{} // 定时查询结果 func (j SmsJob) Exec(args interface{}) error { @@ -31,3 +32,11 @@ func (j SmsPriceJob) Exec(args interface{}) error { return nil } + +func (j SmsCancelPlatformAuto) Exec(args interface{}) error { + phoneService := service.SmsPhone{} + phoneService.Orm = GetDb() + phoneService.Log = logger.NewHelper(logger.DefaultLogger) + + return phoneService.SetManualRenewal() +} diff --git a/config/settings.yml b/config/settings.yml index 0b710d6..8db69c9 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -31,7 +31,7 @@ settings: # sqlserver: sqlserver://用户名:密码@地址?database=数据库名 driver: mysql # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms - source: root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8&parseTime=True&loc=Local&timeout=1000ms + source: root:123456@tcp(127.0.0.1:3306)/proxy_server_prod?charset=utf8&parseTime=True&loc=Local&timeout=1000ms # databases: # 'locaohost:8000': # driver: mysql diff --git a/utils/utility/safe_go_helper.go b/utils/utility/safe_go_helper.go index ddf7a1b..2e4a5da 100644 --- a/utils/utility/safe_go_helper.go +++ b/utils/utility/safe_go_helper.go @@ -5,6 +5,7 @@ import ( "runtime" "runtime/debug" "strings" + "time" "github.com/go-admin-team/go-admin-core/logger" ) @@ -42,3 +43,16 @@ func SafeGoParam[T any](fn func(T), param T) { fn(param) // 执行传入的函数 }() } + +// Retry 重试执行函数,直到成功或达到最大重试次数 +func Retry(max int, delay time.Duration, fn func() error) error { + var err error + for i := 0; i < max; i++ { + err = fn() + if err == nil { + return nil + } + time.Sleep(delay * time.Duration(i+1)) + } + return err +}