diff --git a/.gitattributes b/.gitattributes index 33e08893..c7ea37b8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ * linguist-language=GO -*.xlsx filter=lfs diff=lfs merge=lfs -text diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 32b4d7ff..40aa551a 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -3,6 +3,7 @@ package cmd import ( "context" "kami/internal/controller/apple_card_info" + "kami/utility/cron" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" @@ -45,6 +46,10 @@ var Main = gcmd.Command{ group.Bind(apple_card_info.NewV1()) }) + + //注册轮询任务 + cron.RegisterCron(ctx) + s.Run() return nil }, diff --git a/internal/consts/apple_card.go b/internal/consts/apple_card.go index e1d79575..29c88cb4 100644 --- a/internal/consts/apple_card.go +++ b/internal/consts/apple_card.go @@ -48,11 +48,12 @@ const ( type AppleRechargeOperation string const ( - AppleRechargeOperationCreated AppleRechargeOperation = "创建订单" - AppleRechargeOperationWrongPassword AppleRechargeOperation = "密码错误" - AppleRechargeOperationItunesFail AppleRechargeOperation = "iTunes处理失败(卡密错误)" - AppleRechargeOperationItunesSucceed AppleRechargeOperation = "iTunes处理成功(兑换成功)" - AppleRechargeOperationRepeated AppleRechargeOperation = "重复充值" + AppleRechargeOperationCreated AppleRechargeOperation = "创建订单" + AppleRechargeOperationWrongPassword AppleRechargeOperation = "代充值账户密码错误,等待重新调度" + AppleRechargeOperationItunesFail AppleRechargeOperation = "iTunes处理失败(卡密错误)" + AppleRechargeOperationItunesSucceed AppleRechargeOperation = "iTunes处理成功(兑换成功)" + AppleRechargeOperationItunesSucceedButWrongAmount AppleRechargeOperation = "iTunes处理成功(兑换成功,金额不一致)" + AppleRechargeOperationRepeated AppleRechargeOperation = "重复充值" AppleRechargeOperationStartRechargeByItunes AppleRechargeOperation = "iTunes开始处理" AppleRechargeOperationHandleSuccessByManual AppleRechargeOperation = "手动处理成功" diff --git a/internal/controller/apple_card_info/apple_card_info_v1_call_back_order_manual.go b/internal/controller/apple_card_info/apple_card_info_v1_call_back_order_manual.go index 24d2af5f..5148137b 100644 --- a/internal/controller/apple_card_info/apple_card_info_v1_call_back_order_manual.go +++ b/internal/controller/apple_card_info/apple_card_info_v1_call_back_order_manual.go @@ -2,17 +2,13 @@ package apple_card_info import ( "context" - "fmt" "github.com/gogf/gf/errors/gcode" - "github.com/gogf/gf/v2/os/glog" "kami/api/apple_card_info/v1" "kami/api/commonapi" "kami/internal/consts" "kami/internal/err_handler" "kami/internal/model" "kami/internal/service" - "kami/utility/pool" - "time" ) func (c *ControllerV1) CallBackOrderManual(ctx context.Context, req *v1.CallBackOrderManualReq) (res *v1.CallBackOrderManualRes, err error) { @@ -41,42 +37,13 @@ func (c *ControllerV1) CallBackOrderManual(ctx context.Context, req *v1.CallBack AccountID: orderEntity.AccountId, Operation: consts.AppleRechargeOperationHandleSuccessByManual, }, nil) + //重新获取订单 orderEntity, _ = rechargeOrderService.GetRechargeOrderByOrderNo(ctx, req.OrderNo, req.ID) } - - newPool := pool.New(pool.AppleCardCallBack, 20) - _ = newPool.Add(ctx, func(ctx context.Context) { - for i := 1; i < 4; i++ { - isOk, err2 := rechargeOrderService.CallbackOrder(ctx, orderEntity) - if err2 != nil { - glog.Error(ctx, "手动回调失败,原因:\n", err2) - _ = rechargeOrderService.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ - OrderNo: orderEntity.OrderNo, - RechargeId: orderEntity.Id, - AccountID: orderEntity.AccountId, - Operation: consts.AppleRechargeOperationCallBackFailed, - Remark: fmt.Sprintf("第%d次手动回调失败,原因:%+v", i, err2), - }, nil) - } - if isOk { - _ = rechargeOrderService.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ - OrderNo: orderEntity.OrderNo, - RechargeId: orderEntity.Id, - AccountID: orderEntity.AccountId, - Operation: consts.AppleRechargeOperationCallBackSuccess, - }, nil) - return - } else { - _ = rechargeOrderService.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ - OrderNo: orderEntity.OrderNo, - RechargeId: orderEntity.Id, - AccountID: orderEntity.AccountId, - Operation: consts.AppleRechargeOperationCallBackFailed, - Remark: fmt.Sprintf("第%d次手动回调失败,原因:回调接口返回失败", i), - }, nil) - } - time.Sleep(time.Duration(i*2) * time.Second) - } - }) + err = rechargeOrderService.CallBackOrderToUpstream(ctx, orderEntity) + if err != nil { + err = err_handler.WrapError(ctx, err_handler.CornError, err, "回调网关失败,请稍后重试") + return + } return } diff --git a/internal/controller/apple_card_info/apple_card_info_v1_recharge_handler.go b/internal/controller/apple_card_info/apple_card_info_v1_recharge_handler.go index 360a7932..ecaddf46 100644 --- a/internal/controller/apple_card_info/apple_card_info_v1_recharge_handler.go +++ b/internal/controller/apple_card_info/apple_card_info_v1_recharge_handler.go @@ -30,6 +30,7 @@ func (c *ControllerV1) RechargeHandler(ctx context.Context, req *v1.RechargeHand err = err_handler.WrapError(ctx, gcode.CodeInternalError, err, "分配账户失败") return } + //这个是获取到该账户已经充值成功的金额 todayAmount, err := rechargeOrderService.GetTodayRechargeAmountByAccountID(ctx, accountInfo.Account) if err != nil { err = err_handler.WrapError(ctx, gcode.CodeInternalError, err, "获取今日充值金额失败") diff --git a/internal/controller/apple_card_info/apple_card_info_v1_recharge_itunes_callback.go b/internal/controller/apple_card_info/apple_card_info_v1_recharge_itunes_callback.go index 382f252c..a6feb0a0 100644 --- a/internal/controller/apple_card_info/apple_card_info_v1_recharge_itunes_callback.go +++ b/internal/controller/apple_card_info/apple_card_info_v1_recharge_itunes_callback.go @@ -35,6 +35,7 @@ func (c *ControllerV1) RechargeItunesCallback(ctx context.Context, req *v1.Recha Remark: req.Remark, }, nil) case consts.AppleRechargeItunesStatusSuccess: + //如果当前订单已经处理成功,则不处理 if orderEntity.Status == int(consts.AppleRechargeOrderSuccess) || orderEntity.Status == int(consts.AppleRechargeOrderAmountDifferent) { //添加一条记录 _ = rechargeOrderService.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ @@ -46,9 +47,14 @@ func (c *ControllerV1) RechargeItunesCallback(ctx context.Context, req *v1.Recha }, nil) return } + + var status consts.AppleRechargeOperation + if orderEntity.CardAmount == req.Amount { + status = consts.AppleRechargeOperationItunesSucceed _ = rechargeOrderService.ModifyRechargeOrderStatus(ctx, orderEntity.OrderNo, consts.AppleRechargeOrderSuccess, nil) } else { + status = consts.AppleRechargeOperationItunesSucceedButWrongAmount _ = rechargeOrderService.ModifyRechargeOrderStatus(ctx, orderEntity.OrderNo, consts.AppleRechargeOrderAmountDifferent, nil) } _ = appleAccountService.AddWalletAmount(ctx, model.AppleCardWalletInfo{ @@ -62,9 +68,10 @@ func (c *ControllerV1) RechargeItunesCallback(ctx context.Context, req *v1.Recha AccountID: orderEntity.AccountId, OrderNo: orderEntity.OrderNo, RechargeId: orderEntity.Id, - Operation: consts.AppleRechargeOperationItunesSucceed, + Operation: status, Remark: req.Remark, }, nil) + _ = rechargeOrderService.CallBackOrderToUpstream(ctx, orderEntity) case consts.AppleRechargeItunesStatusFail: _ = rechargeOrderService.ModifyRechargeOrderStatus(ctx, orderEntity.OrderNo, consts.AppleRechargeOrderFail, nil) //添加一条记录 diff --git a/internal/err_handler/code.go b/internal/err_handler/code.go index ea5f13fd..e9236b76 100644 --- a/internal/err_handler/code.go +++ b/internal/err_handler/code.go @@ -12,4 +12,5 @@ var ( ErrFileBroken = gcode.New(2006, "文件损坏", nil) HttpClientGetError = gcode.New(1005, "http请求失败", nil) + CornError = gcode.New(2001, "处理错误,请稍后重试", nil) ) diff --git a/internal/logic/apple_card_account/account.go b/internal/logic/apple_card_account/account.go index ca031a3f..a0c83c4c 100644 --- a/internal/logic/apple_card_account/account.go +++ b/internal/logic/apple_card_account/account.go @@ -149,7 +149,7 @@ func (a *sAppleAccount) GetAccordingAccount(ctx context.Context) (data entity.V1 return } -// 获取所有账号 +// GetAllAccount 获取所有账号 func (a *sAppleAccount) GetAllAccount(ctx context.Context) (data []entity.V1CardAppleAccountInfo, err error) { data = make([]entity.V1CardAppleAccountInfo, 0) err = dao.V1CardAppleAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()). @@ -159,3 +159,33 @@ func (a *sAppleAccount) GetAllAccount(ctx context.Context) (data []entity.V1Card } return } + +// GetAllAccountByStatus 获取所有可用的账号 +func (a *sAppleAccount) GetAllAccountByStatus(ctx context.Context, status consts.AppleAccountStatus) (data []entity.V1CardAppleAccountInfo, err error) { + data = make([]entity.V1CardAppleAccountInfo, 0) + err = dao.V1CardAppleAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()). + WhereNot(dao.V1CardAppleAccountInfo.Columns().Status, consts.AppleAccountWrongPassword). + WhereNot(dao.V1CardAppleAccountInfo.Columns().Status, consts.AppleAccountForbidden). + Scan(&data) + if gerror.Equal(err, sql.ErrNoRows) { + err = nil + } + return +} + +// ResetAccountStatus 重置账号状态 +func (a *sAppleAccount) ResetAccountStatus(ctx context.Context) (err error) { + //所有账户今日交易量和交易订单金额清零 + _, err = dao.V1CardAppleAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()). + Update(do.V1CardAppleAccountInfo{ + TodayRechargeAmount: 0, + TodayRechargeCount: 0, + }) + //所有交易满额的账户取消限制 + _, err = dao.V1CardAppleAccountInfo.Ctx(ctx).DB(config.GetDatabaseV1()). + Where(dao.V1CardAppleAccountInfo.Columns().Status, consts.AppleAccountLimited). + Update(do.V1CardAppleAccountInfo{ + Status: consts.AppleAccountNormal, + }) + return +} diff --git a/internal/logic/apple_card_recharge_history/recharge_history.go b/internal/logic/apple_card_recharge_history/recharge_history.go index 9bf2eee1..78b4257a 100644 --- a/internal/logic/apple_card_recharge_history/recharge_history.go +++ b/internal/logic/apple_card_recharge_history/recharge_history.go @@ -16,6 +16,8 @@ import ( "github.com/google/uuid" "io" "kami/internal/err_handler" + "kami/utility/pool" + "time" "kami/internal/consts" "kami/internal/dao" @@ -209,12 +211,14 @@ func (h *sRechargeHistory) GetRechargeDetails(ctx context.Context, orderNo strin // GetTodayRechargeAmountByAccountID 获取当前账户今日的充值金额 func (h *sRechargeHistory) GetTodayRechargeAmountByAccountID(ctx context.Context, accountID string) (amount float64, err error) { - // 定义进入0点的变量 year, month, day := gtime.Now().Date() amount, err = dao.V1CardAppleRechargeInfo.Ctx(ctx).DB(config.GetDatabaseV1()). - WhereNot(dao.V1CardAppleRechargeInfo.Columns().Status, consts.AppleRechargeOrderFail). + Where(dao.V1CardAppleRechargeInfo.Columns().AccountId, accountID). + Where(dao.V1CardAppleRechargeInfo.Columns().Status, consts.AppleRechargeOrderProcessing). + Where(dao.V1CardAppleRechargeInfo.Columns().Status, consts.AppleRechargeOrderSuccess). + Where(dao.V1CardAppleRechargeInfo.Columns().Status, consts.AppleRechargeOrderAmountDifferent). WhereBetween(dao.V1CardAppleRechargeInfo.Columns().CreatedAt, gtime.NewFromStr(fmt.Sprintf("%d-%d-%d 00:00:00", year, month, day)), gtime.Now()). - Sum(dao.V1CardAppleRechargeInfo.Columns().CardAmount) + Sum(dao.V1CardAppleRechargeInfo.Columns().ActualAmount) return } @@ -342,3 +346,41 @@ func (h *sRechargeHistory) CallbackOrder(ctx context.Context, data entity.V1Card // 修改订单状态 return true, nil } + +func (h *sRechargeHistory) CallBackOrderToUpstream(ctx context.Context, orderEntity entity.V1CardAppleRechargeInfo) (err error) { + newPool := pool.New(pool.AppleCardCallBack, 20) + err = newPool.Add(ctx, func(ctx context.Context) { + for i := 1; i < 4; i++ { + isOk, err2 := h.CallbackOrder(ctx, orderEntity) + if err2 != nil { + glog.Error(ctx, "手动回调失败,原因:\n", err2) + _ = h.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ + OrderNo: orderEntity.OrderNo, + RechargeId: orderEntity.Id, + AccountID: orderEntity.AccountId, + Operation: consts.AppleRechargeOperationCallBackFailed, + Remark: fmt.Sprintf("第%d次手动回调失败,原因:%+v", i, err2), + }, nil) + } + if isOk { + _ = h.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ + OrderNo: orderEntity.OrderNo, + RechargeId: orderEntity.Id, + AccountID: orderEntity.AccountId, + Operation: consts.AppleRechargeOperationCallBackSuccess, + }, nil) + return + } else { + _ = h.AddHistory(ctx, model.AppleCardRechargeHistoryInput{ + OrderNo: orderEntity.OrderNo, + RechargeId: orderEntity.Id, + AccountID: orderEntity.AccountId, + Operation: consts.AppleRechargeOperationCallBackFailed, + Remark: fmt.Sprintf("第%d次手动回调失败,原因:回调接口返回失败", i), + }, nil) + } + time.Sleep(time.Duration(i*2) * time.Second) + } + }) + return +} diff --git a/internal/logic/user_center/user_center.go b/internal/logic/user_center/user_center.go index 0f79c8af..75d9de78 100644 --- a/internal/logic/user_center/user_center.go +++ b/internal/logic/user_center/user_center.go @@ -57,12 +57,12 @@ func (c *sUserCenter) CheckPassword(ctx context.Context, oldPassword, newPasswor return false, err } - frontendResult, err := verify.AesCBCDecryptWithBase64(newPassword, []byte(frontendModel.Key), []byte(frontendModel.IV)) + frontendResult, err := verify.AesCBCStdDecryptWithBase64(newPassword, []byte(frontendModel.Key), []byte(frontendModel.IV)) if err != nil { return false, err } - backendResult, err := verify.AesCBCDecryptWithBase64(oldPassword, []byte(backendModel.Key), []byte(backendModel.IV)) + backendResult, err := verify.AesCBCStdDecryptWithBase64(oldPassword, []byte(backendModel.Key), []byte(backendModel.IV)) if err != nil { return false, err } @@ -93,7 +93,7 @@ func (c *sUserCenter) ReGeneratePassword(ctx context.Context, password string) ( return "", err } - frontendResult, err := verify.AesCBCDecryptWithBase64(password, []byte(frontendModel.Key), []byte(frontendModel.IV)) + frontendResult, err := verify.AesCBCStdDecryptWithBase64(password, []byte(frontendModel.Key), []byte(frontendModel.IV)) if err != nil { return "", err } diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index 6c379d3f..5e3fc64a 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -100,7 +100,7 @@ func IFrameAuth(r *ghttp.Request) { }) return } - tokenByte, err := verify.AesCBCDecryptWithBase64(tokenStr, []byte(frontendModel.Key), []byte(frontendModel.IV)) + tokenByte, err := verify.AesCBCURLDecryptWithBase64(tokenStr, []byte(frontendModel.Key), []byte(frontendModel.IV)) if err != nil { glog.Error(ctx, "解析Token错误", tokenStr, err) r.Response.WriteJson(token.AuthFailed{ diff --git a/internal/service/apple_card_account.go b/internal/service/apple_card_account.go index 043de192..fd7d4ea5 100644 --- a/internal/service/apple_card_account.go +++ b/internal/service/apple_card_account.go @@ -32,8 +32,12 @@ type ( GetDetailByAccount(ctx context.Context, account string) (data entity.V1CardAppleAccountInfo, err error) // GetAccordingAccount 轮播,获取符合条件的第一个账户 GetAccordingAccount(ctx context.Context) (data entity.V1CardAppleAccountInfo, err error) - // 获取所有账号 + // GetAllAccount 获取所有账号 GetAllAccount(ctx context.Context) (data []entity.V1CardAppleAccountInfo, err error) + // GetAllAccountByStatus 获取所有可用的账号 + GetAllAccountByStatus(ctx context.Context, status consts.AppleAccountStatus) (data []entity.V1CardAppleAccountInfo, err error) + // ResetAccountStatus 重置账号状态 + ResetAccountStatus(ctx context.Context) (err error) } ) diff --git a/internal/service/apple_card_recharge_history.go b/internal/service/apple_card_recharge_history.go index f1637bf1..4348a341 100644 --- a/internal/service/apple_card_recharge_history.go +++ b/internal/service/apple_card_recharge_history.go @@ -51,6 +51,7 @@ type ( QueryFaceValueByZHL(ctx context.Context, cardNo string) (bool, error) // CallbackOrder 回调订单给第三方 CallbackOrder(ctx context.Context, data entity.V1CardAppleRechargeInfo) (bool, error) + CallBackOrderToUpstream(ctx context.Context, orderEntity entity.V1CardAppleRechargeInfo) (err error) } ) diff --git a/manifest/config/config.yaml b/manifest/config/config.yaml index bcec79b8..c1c43424 100644 --- a/manifest/config/config.yaml +++ b/manifest/config/config.yaml @@ -1,5 +1,5 @@ server: - address: ":12401" + address: ":8000" NameToUriType: 3 maxHeaderBytes: "20KB" clientMaxBodySize: "50MB" diff --git a/manifest/docker/Dockerfile b/manifest/docker/Dockerfile index 3bae9dd8..b4ab708f 100644 --- a/manifest/docker/Dockerfile +++ b/manifest/docker/Dockerfile @@ -21,6 +21,7 @@ RUN echo "https://mirrors.aliyun.com/alpine/v3.18/main/" > /etc/apk/repositories echo "Asia/Shanghai" > /etc/timezone COPY --from=builder /build/main /app/ +COPY --from=builder /build/resource/public/ /app/resource/public/ # 启动服务 CMD ["./main"] diff --git a/utility/cron/cron.go b/utility/cron/cron.go new file mode 100644 index 00000000..26dc0f4b --- /dev/null +++ b/utility/cron/cron.go @@ -0,0 +1,18 @@ +package cron + +import ( + "github.com/gogf/gf/v2/os/gcron" + "github.com/gogf/gf/v2/os/glog" + "golang.org/x/net/context" + "kami/internal/service" +) + +// RegisterCron 注册定时任务 +func RegisterCron(ctx context.Context) { + //每日0时执行 + _, _ = gcron.Add(ctx, "0 0 0 * * ?", func(ctx context.Context) { + glog.Info(ctx, "每日0时执行,重置苹果账户状态") + accountService := service.AppleAccount() + _ = accountService.ResetAccountStatus(ctx) + }) +} diff --git a/utility/verify/aes_ecb.go b/utility/verify/aes_ecb.go index bb4f704e..8b1ebe14 100644 --- a/utility/verify/aes_ecb.go +++ b/utility/verify/aes_ecb.go @@ -56,7 +56,7 @@ func aesCBCDecrypt(ciphertext []byte, key []byte, iv []byte) ([]byte, error) { return result, nil } -func AesCBCDecryptWithBase64(ciphertext string, key []byte, iv []byte) ([]byte, error) { +func AesCBCStdDecryptWithBase64(ciphertext string, key []byte, iv []byte) ([]byte, error) { text, err := base64.StdEncoding.DecodeString(ciphertext) if err != nil { return text, err @@ -64,6 +64,14 @@ func AesCBCDecryptWithBase64(ciphertext string, key []byte, iv []byte) ([]byte, return aesCBCDecrypt(text, key, iv) } +func AesCBCURLDecryptWithBase64(ciphertext string, key []byte, iv []byte) ([]byte, error) { + text, err := base64.URLEncoding.DecodeString(ciphertext) + if err != nil { + return text, err + } + return aesCBCDecrypt(text, key, iv) +} + // PKCS7 填充 func paddingPKCS7(plaintext []byte, blockSize int) []byte { paddingSize := blockSize - len(plaintext)%blockSize