package notify import ( "context" "encoding/json" "io" "net/http" "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/model/order" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/pkg/appleiap" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/payment" queueType "github.com/perfect-panel/server/queue/types" ) // AppleIAPNotifyLogic 处理 Apple Server Notifications v2 的逻辑 // 功能: 验签与事件解析(此处提供最小骨架),将续期/初购事件转换为订单并入队赋权 // 参数: HTTP 请求 // 返回: 错误信息 type AppleIAPNotifyLogic struct { logger.Logger ctx context.Context svcCtx *svc.ServiceContext } // NewAppleIAPNotifyLogic 创建逻辑实例 // 参数: 上下文, 服务上下文 // 返回: 逻辑指针 func NewAppleIAPNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AppleIAPNotifyLogic { return &AppleIAPNotifyLogic{Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx} } // AppleNotification 简化的通知结构(骨架) type rawPayload struct { SignedPayload string `json:"signedPayload"` } type transactionInfo struct { OriginalTransactionId string `json:"originalTransactionId"` TransactionId string `json:"transactionId"` ProductId string `json:"productId"` } // Handle 处理通知 // 参数: *http.Request // 返回: error func (l *AppleIAPNotifyLogic) Handle(r *http.Request) error { body, _ := io.ReadAll(r.Body) var rp rawPayload if err := json.Unmarshal(body, &rp); err != nil { l.Errorw("[AppleIAP] Unmarshal request failed", logger.Field("error", err.Error())) return err } claims, env, err := appleiap.VerifyAutoEnv(rp.SignedPayload) if err != nil { l.Errorw("[AppleIAP] Verify payload failed", logger.Field("error", err.Error())) return err } t, _ := claims["notificationType"].(string) data, _ := claims["data"].(map[string]interface{}) sti, _ := data["signedTransactionInfo"].(string) txClaims, err := appleiap.VerifyWithEnv(env, sti) if err != nil { l.Errorw("[AppleIAP] Verify transaction failed", logger.Field("error", err.Error())) return err } b, _ := json.Marshal(txClaims) var tx transactionInfo _ = json.Unmarshal(b, &tx) switch t { case "INITIAL_BUY": return l.processInitialBuy(env, tx) case "DID_RENEW": return l.processRenew(env, tx) default: return nil } } // createPaidOrderAndEnqueue 创建已支付订单并入队赋权/续费 // 参数: AppleNotification, 订单类型 // 返回: error func (l *AppleIAPNotifyLogic) processInitialBuy(env string, tx transactionInfo) error { if tx.OriginalTransactionId == "" || tx.TransactionId == "" { return nil } // if order already exists, ignore if oi, err := l.svcCtx.OrderModel.FindOneByTradeNo(l.ctx, tx.OriginalTransactionId); err == nil && oi != nil { return nil } return nil } func (l *AppleIAPNotifyLogic) processRenew(env string, tx transactionInfo) error { if tx.OriginalTransactionId == "" || tx.TransactionId == "" { return nil } oi, err := l.svcCtx.OrderModel.FindOneByTradeNo(l.ctx, tx.OriginalTransactionId) if err != nil || oi == nil { return nil } o := &order.Order{ UserId: oi.UserId, OrderNo: tx.TransactionId, Type: 2, Quantity: 1, Price: 0, Amount: 0, Discount: 0, Coupon: "", CouponDiscount: 0, PaymentId: 0, Method: payment.AppleIAP.String(), FeeAmount: 0, Status: 2, IsNew: false, SubscribeId: oi.SubscribeId, TradeNo: tx.OriginalTransactionId, SubscribeToken: oi.SubscribeToken, } if err := l.svcCtx.OrderModel.Insert(l.ctx, o); err != nil { return err } payload := queueType.ForthwithActivateOrderPayload{OrderNo: o.OrderNo} bytes, _ := json.Marshal(payload) task := asynq.NewTask(queueType.ForthwithActivateOrder, bytes) if _, err := l.svcCtx.Queue.EnqueueContext(l.ctx, task); err != nil { return err } return nil }