You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.3 KiB
91 lines
2.3 KiB
package appleiap
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
)
|
|
|
|
type ISys interface {
|
|
GenerateOrderNo(prefix string) string
|
|
// VerifyReceipt 校验 base64 的收据(legacy verifyReceipt 或 App Store Server API)
|
|
VerifyReceipt(ctx context.Context, receiptData string) (bool, error)
|
|
// VerifyTransaction 校验交易 ID(使用 App Store Server API 查询)
|
|
VerifyTransaction(ctx context.Context, transactionId string) (bool, error)
|
|
}
|
|
|
|
// defsys 由 OnInit(启动) 与 Reload(运行时热更) 写、各包级函数读,故必须加锁:
|
|
// 无锁并发读写接口值是 data race。
|
|
var (
|
|
mu sync.RWMutex
|
|
defsys ISys
|
|
)
|
|
|
|
// ErrNotInited 苹果内购未初始化。OnInit 失败时调用方可选择降级;此时包级函数返回本错误,而不是 panic。
|
|
var ErrNotInited = errors.New("appleiap 未初始化:配置缺失或密钥加载失败")
|
|
|
|
func get() ISys {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
return defsys
|
|
}
|
|
|
|
func set(sys ISys) {
|
|
mu.Lock()
|
|
defsys = sys
|
|
mu.Unlock()
|
|
}
|
|
|
|
func OnInit(config map[string]interface{}, option ...Option) error {
|
|
sys, err := newSys(newOptions(config, option...))
|
|
if err != nil {
|
|
// 出错时不要给 defsys 赋值,避免「非 nil 接口 + nil 指针」让守卫失效。
|
|
return err
|
|
}
|
|
set(sys)
|
|
return nil
|
|
}
|
|
|
|
// Reload 运行时热替换苹果内购客户端(console 后台改配置后由业务侧调用)。
|
|
// 配置不合法时返回 error 且**保留原客户端不动**;启动时未初始化的场景下,
|
|
// 后台首次配好凭据即经此启用,无需重启。
|
|
func Reload(config map[string]interface{}, option ...Option) error {
|
|
sys, err := newSys(newOptions(config, option...))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
set(sys)
|
|
return nil
|
|
}
|
|
|
|
func NewSys(option ...Option) (ISys, error) {
|
|
sys, err := newSys(newOptionsByOption(option...))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sys, nil
|
|
}
|
|
|
|
func GenerateOrderNo(prefix string) string {
|
|
sys := get()
|
|
if sys == nil {
|
|
return ""
|
|
}
|
|
return sys.GenerateOrderNo(prefix)
|
|
}
|
|
|
|
func VerifyReceipt(ctx context.Context, receiptData string) (bool, error) {
|
|
sys := get()
|
|
if sys == nil {
|
|
return false, ErrNotInited
|
|
}
|
|
return sys.VerifyReceipt(ctx, receiptData)
|
|
}
|
|
|
|
func VerifyTransaction(ctx context.Context, transactionId string) (bool, error) {
|
|
sys := get()
|
|
if sys == nil {
|
|
return false, ErrNotInited
|
|
}
|
|
return sys.VerifyTransaction(ctx, transactionId)
|
|
}
|
|
|