|
|
@ -9,57 +9,68 @@ import (
|
|
|
|
"sync"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Order represents an order object used for signing parameters
|
|
|
|
// Order 表示订单对象,用于签名参数
|
|
|
|
type Order struct {
|
|
|
|
type Order struct {
|
|
|
|
Uid string
|
|
|
|
Uid string // 用户ID
|
|
|
|
BsTradeNo string
|
|
|
|
BsTradeNo string // 交易编号
|
|
|
|
Role string
|
|
|
|
Role string // 用户角色
|
|
|
|
RoleId string
|
|
|
|
RoleId string // 角色ID
|
|
|
|
ServerId string
|
|
|
|
ServerId string // 服务器ID
|
|
|
|
GoodsName string
|
|
|
|
GoodsName string // 商品名称
|
|
|
|
OutTradeNo string
|
|
|
|
OutTradeNo string // 外部交易编号
|
|
|
|
Body string
|
|
|
|
Body string // 商品描述
|
|
|
|
CpExtraInfo string
|
|
|
|
CpExtraInfo string // 扩展信息
|
|
|
|
TradeState string
|
|
|
|
TradeState string // 交易状态
|
|
|
|
TotalFee string
|
|
|
|
TotalFee string // 总费用
|
|
|
|
PayFee string
|
|
|
|
PayFee string // 支付费用
|
|
|
|
PayTime string
|
|
|
|
PayTime string // 支付时间
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Config holds the configuration for SDK, such as appId and secret keys
|
|
|
|
// Config 用于保存SDK的配置信息,例如appId和secretKey
|
|
|
|
type Config struct {
|
|
|
|
type Config struct {
|
|
|
|
SecretKey string
|
|
|
|
SecretKey string // 秘钥
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SDK struct encapsulates SDK configuration and utility functions
|
|
|
|
// SDK结构体封装了SDK的配置和工具函数
|
|
|
|
type SDK struct {
|
|
|
|
type SDK struct {
|
|
|
|
SecretKey string
|
|
|
|
SecretKey string // 秘钥
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Singleton instance and mutex for thread safety
|
|
|
|
// 单例实例和互斥锁,确保线程安全
|
|
|
|
var instance *SDK
|
|
|
|
var instance *SDK
|
|
|
|
var once2 sync.Once
|
|
|
|
var onces sync.Once
|
|
|
|
|
|
|
|
|
|
|
|
// New initializes a new SDK with the given configuration, but ensures that only one instance exists.
|
|
|
|
// New 返回一个SDK单例实例,初始化时传入秘钥
|
|
|
|
func New(secretKey string) *SDK {
|
|
|
|
func New(secretKey string) *SDK {
|
|
|
|
once2.Do(func() {
|
|
|
|
onces.Do(func() {
|
|
|
|
instance = &SDK{
|
|
|
|
instance = &SDK{
|
|
|
|
SecretKey: secretKey,
|
|
|
|
SecretKey: secretKey,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
return instance
|
|
|
|
return instance // 返回单例实例
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Md5String generates MD5 hash of a given string
|
|
|
|
// Md5String 生成给定字符串的MD5哈希值并返回十六进制字符串
|
|
|
|
func (s *SDK) Md5String(str string) string {
|
|
|
|
func (s *SDK) Md5String(str string) string {
|
|
|
|
hash := md5.Sum([]byte(str)) // Use md5.Sum for fixed size output
|
|
|
|
hash := md5.Sum([]byte(str)) // 计算MD5哈希
|
|
|
|
return hex.EncodeToString(hash[:])
|
|
|
|
return hex.EncodeToString(hash[:]) // 转为十六进制字符串并返回
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SignParam generates a signed URL-encoded string for the provided Order object
|
|
|
|
// SignParam 为提供的Order对象生成签名
|
|
|
|
func (s *SDK) SignParam(order *Order) (string, error) {
|
|
|
|
func (s *SDK) SignParam(order *Order) (string, error) {
|
|
|
|
// Create a map of the parameters to be signed
|
|
|
|
// 创建待签名参数映射
|
|
|
|
paramMap := map[string]string{
|
|
|
|
paramMap := s.createParamMap(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 按照字典顺序排序并生成待签名字符串
|
|
|
|
|
|
|
|
signStr := s.buildSignString(paramMap)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算最终签名并返回
|
|
|
|
|
|
|
|
return s.Md5String(signStr), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// createParamMap 构建参数映射,跳过 "sign" 和 "-" 键
|
|
|
|
|
|
|
|
func (s *SDK) createParamMap(order *Order) map[string]string {
|
|
|
|
|
|
|
|
return map[string]string{
|
|
|
|
"uid": order.Uid,
|
|
|
|
"uid": order.Uid,
|
|
|
|
"bs_trade_no": order.BsTradeNo,
|
|
|
|
"bs_trade_no": order.BsTradeNo,
|
|
|
|
"role": order.Role,
|
|
|
|
"role": order.Role,
|
|
|
@ -73,43 +84,46 @@ func (s *SDK) SignParam(order *Order) (string, error) {
|
|
|
|
"total_fee": order.TotalFee,
|
|
|
|
"total_fee": order.TotalFee,
|
|
|
|
"pay_fee": order.PayFee,
|
|
|
|
"pay_fee": order.PayFee,
|
|
|
|
"pay_time": order.PayTime,
|
|
|
|
"pay_time": order.PayTime,
|
|
|
|
"sign": "",
|
|
|
|
"sign": "", // 初始化签名为空
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Generate the signed value
|
|
|
|
// buildSignString 按照字典顺序排序参数并拼接成签名字符串
|
|
|
|
signStr := s.SortMapString(paramMap) + s.SecretKey
|
|
|
|
func (s *SDK) buildSignString(params map[string]string) string {
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
|
|
|
keys := s.getSortedKeys(params) // 获取排序后的键
|
|
|
|
|
|
|
|
|
|
|
|
// Return the MD5 hash
|
|
|
|
// 拼接所有键对应的值
|
|
|
|
return s.Md5String(signStr), nil
|
|
|
|
for _, k := range keys {
|
|
|
|
|
|
|
|
builder.WriteString(params[k])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SortMapString sorts the keys of a map and returns a concatenated string
|
|
|
|
// 将秘钥追加到签名字符串后
|
|
|
|
func (s *SDK) SortMapString(params map[string]string) string {
|
|
|
|
builder.WriteString(s.SecretKey)
|
|
|
|
var builder strings.Builder
|
|
|
|
|
|
|
|
keys := make([]string, 0, len(params))
|
|
|
|
return builder.String()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Avoid sorting the "sign" and "-" keys
|
|
|
|
// getSortedKeys 返回排除 "sign" 和 "-" 键后的排序键列表
|
|
|
|
|
|
|
|
func (s *SDK) getSortedKeys(params map[string]string) []string {
|
|
|
|
|
|
|
|
var keys []string
|
|
|
|
for k := range params {
|
|
|
|
for k := range params {
|
|
|
|
|
|
|
|
// 跳过 "sign" 和 "-" 键
|
|
|
|
if k == "sign" || k == "-" {
|
|
|
|
if k == "sign" || k == "-" {
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keys = append(keys, k)
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Strings(keys) // Sort the keys
|
|
|
|
sort.Strings(keys) // 排序键
|
|
|
|
|
|
|
|
return keys
|
|
|
|
// Efficiently concatenate the values
|
|
|
|
|
|
|
|
for _, k := range keys {
|
|
|
|
|
|
|
|
builder.WriteString(params[k])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return builder.String()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ToJson converts an interface{} to JSON string
|
|
|
|
// ToJson 将一个接口类型转换为JSON字符串
|
|
|
|
func (s *SDK) ToJson(item interface{}) (string, error) {
|
|
|
|
func (s *SDK) ToJson(item interface{}) (string, error) {
|
|
|
|
|
|
|
|
// 使用json.Marshal将对象转换为JSON
|
|
|
|
res, err := json.Marshal(item)
|
|
|
|
res, err := json.Marshal(item)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return "", err // Simplified error handling
|
|
|
|
return "", err // 返回错误
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string(res), nil
|
|
|
|
return string(res), nil // 返回JSON字符串
|
|
|
|
}
|
|
|
|
}
|
|
|
|