Files
utility_go/package/pay/apple.go
2025-02-28 17:45:44 +08:00

157 lines
5.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package pay
import (
"context"
"github.com/go-pay/gopay/apple"
"github.com/gogf/gf/v2/errors/gerror"
"strings"
"sync"
"time"
)
// ApplePay 苹果支付
// 这是一个用于处理苹果支付的结构体。
type ApplePay struct {
pass string // pass 是用于苹果支付过程中的密钥。
lock sync.RWMutex // lock 用于确保在并发访问或修改 pass 时的安全性。
}
// Init 是ApplePay类型的初始化函数。
//
// @Description: 对ApplePay对象进行初始化将传入的数据存储到对象中。
// @receiver p: ApplePay对象的指针用于接收初始化操作。
// @param data: 一个字节切片,包含需要初始化的数据。
func (p *ApplePay) Init(data []byte) {
p.lock.Lock() // 加锁以保证在多线程环境下的线程安全
defer p.lock.Unlock() // 确保在函数执行完毕退出时自动解锁,避免死锁
p.pass = string(data) // 将传入的字节切片数据转换为字符串并赋值给pass字段
}
// VerifyPay 验证苹果支付
//
// @Description: 验证苹果支付的收据信息,以确认支付的有效性。
// @receiver p *ApplePay: ApplePay对象用于执行验证支付的操作。
// @param userId uint64: 用户ID。
// @param OrderId string: 订单ID。
// @param package1 string: 付费产品的包装名称。
// @param subscriptionID string: 订阅ID。
// @param purchaseToken string: 购买令牌,用于苹果服务器的收据验证。
// @param isDebug bool: 是否为调试模式决定使用哪个验证URL。
// @param cb func(string) error: 回调函数用于处理验证成功后的产品ID。
// @return error: 返回错误信息,如果验证过程中出现错误,则返回相应的错误信息。
func (p *ApplePay) VerifyPay(userId uint64, OrderId, package1, subscriptionID, purchaseToken string, isDebug bool, cb func(string) error) error {
p.lock.RLock() // 加读锁,保证并发安全
defer p.lock.RUnlock() // 解读锁,确保函数执行完毕后释放锁
// 根据是否为调试模式选择验证URL
url := apple.UrlProd
if isDebug {
url = apple.UrlSandbox
}
// 向苹果服务器验证收据
info, err := apple.VerifyReceipt(context.Background(), url, p.pass, purchaseToken)
if err != nil {
// 如果验证失败,则返回错误
return err
}
// 检查收据验证的状态
if info.Status == 0 {
// 检查收据中是否包含内购信息
if len(info.Receipt.InApp) <= 0 {
return gerror.Wrap(err, "info.Receipt.InApp = 0")
}
// 调用回调函数处理商品ID
if err := cb(info.Receipt.InApp[0].ProductId); err != nil {
// 如果回调处理失败,则返回错误
return err
}
} else {
// 如果收据验证状态异常,则返回状态错误信息
return gerror.Wrapf(err, "status err = %v", info.Status)
}
return nil
}
// VerifyPayV1 验证苹果支付的交易
//
// @Description:
// @receiver p
// @param purchaseToken
// @param isDebug
// @param cb
// @return error
func (p *ApplePay) VerifyPayV1(purchaseToken string, isDebug bool, cb func(string, string) error) error {
p.lock.RLock() // 加读锁,确保并发安全
defer p.lock.RUnlock() // 结束时自动释放读锁
// 根据调试模式选择验证服务的URL
url := apple.UrlProd
if isDebug {
url = apple.UrlSandbox
}
// 向苹果服务器验证收据
info, err := apple.VerifyReceipt(context.Background(), url, p.pass, purchaseToken)
if err != nil {
// 验证失败,返回错误
return err
}
// 检查验证结果状态
if info.Status == 0 {
// 验证成功,检查收据中是否有内购信息
if len(info.Receipt.InApp) <= 0 {
// 收据中无内购信息,返回错误
return gerror.Wrap(err, "info.Receipt.InApp = 0")
}
// 调用回调函数,处理内购产品信息
if err := cb(info.Receipt.InApp[0].ProductId, info.Receipt.InApp[0].OriginalTransactionId); err != nil {
// 回调函数执行失败,返回错误
return gerror.Wrap(err, "回调函数执行失败")
}
} else {
// 验证结果状态异常,返回错误
return gerror.Wrapf(err, "status err = %v", info.Status)
}
// 验证成功返回nil
return nil
}
// VerifyPayTest 用于验证苹果支付的测试购买。
//
// @Description:
// @receiver p
// @param purchaseToken
// @return interface{}
// @return error
func (p *ApplePay) VerifyPayTest(purchaseToken string) (interface{}, error) {
// 使用沙箱环境的URL进行验证
url := apple.UrlSandbox
// 调用apple.VerifyReceipt进行收据验证
return apple.VerifyReceipt(context.Background(), url, p.pass, purchaseToken)
}
// GetTime 根据提供的 timer 字符串解析时间,格式为 "YYYY-MM-DD HH:MM:SS ZZZ",若解析失败则返回当前时间
//
// @Description: 根据指定格式解析时间字符串,如果解析失败或者格式不正确,则返回当前时间。
// @param timer 时间字符串,格式为 "YYYY-MM-DD HH:MM:SS ZZZ",其中 ZZZ 为时区标识。
// @return time.Time 解析得到的时间,若失败则返回当前时间。
func GetTime(timer string) time.Time {
// 将 timer 字符串按空格分割为年月日和时分秒两部分
ts := strings.Split(timer, "")
// 如果分割后的数组长度不为3则说明格式不正确返回当前时间
if len(ts) != 3 {
return time.Now()
}
// 尝试加载指定时区信息
location, err := time.LoadLocation(ts[2])
// 如果加载时区失败,则返回当前时间
if err != nil {
return time.Now()
}
// 使用指定时区解析时间字符串
t, err := time.ParseInLocation("2006-01-02 15:04:05 MST", ts[0]+" "+ts[1], location)
// 如果解析失败,则返回当前时间
if err != nil {
return time.Now()
}
// 将解析得到的时间转换为本地时间并返回
return t.In(time.Local)
}