Compare commits

...

7 Commits

Author SHA1 Message Date
70a5b3db89 新增自定义时间记录 2025-09-17 17:40:31 +08:00
40bd9bb254 游戏日志方法封装 2025-09-12 18:47:14 +08:00
ayflying
4473003a36 荣耀消耗后打印更多日志 2025-09-10 12:15:25 +08:00
ayflying
e5e6068337 修改荣耀消耗使用ClientSecret 2025-09-09 15:56:46 +08:00
ayflying
1355634c22 返回荣耀消耗的错误类型 2025-09-09 14:51:26 +08:00
ayflying
2709af041b 新增写失败也会跳过,下次再执行 2025-09-03 14:37:05 +08:00
ayflying
33c8712c72 去掉更新日志 2025-09-03 13:46:39 +08:00
5 changed files with 145 additions and 23 deletions

View File

@@ -471,9 +471,9 @@ func (s *sGameAct) Cache2Sql(ctx context.Context, add, update []*entity.GameAct)
// Cache2AddChan 批量添加数据库 // Cache2AddChan 批量添加数据库
func (s *sGameAct) Cache2SqlChan(ctx context.Context, addChan, updateChan chan *entity.GameAct) { func (s *sGameAct) Cache2SqlChan(ctx context.Context, addChan, updateChan chan *entity.GameAct) {
//批量写入数据库计数 //批量写入数据库计数
var addCount int var addCount int64
//批量更新数据库计数 //批量更新数据库计数
var updateCount int var updateCount int64
//通道关闭标志 //通道关闭标志
addClosed := false addClosed := false
updateClosed := false updateClosed := false
@@ -499,10 +499,11 @@ func (s *sGameAct) Cache2SqlChan(ctx context.Context, addChan, updateChan chan *
continue continue
} }
if row, _ := addRes.RowsAffected(); row == 0 { if row, _ := addRes.RowsAffected(); row == 0 {
g.Log().Error(ctx, "本次新增为0新增数据失败: %v", v) //g.Log().Error(ctx, "本次新增为0新增数据失败: %v", v)
continue continue
} }
addCount++ row, _ := addRes.RowsAffected()
addCount += row
//删除缓存 //删除缓存
s.DelCacheKey(ctx, v.ActId, v.Uid) s.DelCacheKey(ctx, v.ActId, v.Uid)
@@ -521,7 +522,7 @@ func (s *sGameAct) Cache2SqlChan(ctx context.Context, addChan, updateChan chan *
continue continue
} }
if row, _ := updateRes.RowsAffected(); row == 0 { if row, _ := updateRes.RowsAffected(); row == 0 {
g.Log().Error(ctx, "本次更新为0更新数据失败: %v", v) //g.Log().Error(ctx, "本次更新为0更新数据失败: %v", v)
continue continue
} }
//删除缓存 //删除缓存

View File

@@ -268,25 +268,66 @@ func (sdk *SDK) Shutdown() {
const datetimeFmt = time.DateOnly + " " + time.TimeOnly const datetimeFmt = time.DateOnly + " " + time.TimeOnly
// 记录日志 // 记录日志
func (sdk *SDK) Log(uid, event string, property map[string]any, timezone string) { func (sdk *SDK) Log(uid, event string, property map[string]any, timezone string, customEventTime ...time.Time) {
loc := time.Local loc := time.Local
if _loc := getLocationMapValue(timezone); _loc != nil { if _loc := getLocationMapValue(timezone); _loc != nil {
loc = _loc loc = _loc
} }
if len(property) == 0 {
property = map[string]any{"ts": gtime.Now().Timestamp()}
}
var et *gtime.Time
if len(customEventTime) > 0 {
et = gtime.NewFromTime(customEventTime[0])
} else {
et = gtime.Now()
}
log := GameLog{ log := GameLog{
Uid: uid, Uid: uid,
Event: event, Event: event,
Property: property, Property: property,
EventTimems: gtime.Now().TimestampMilli(), EventTimems: et.TimestampMilli(),
EventTimeLoc: gtime.Now().In(loc).Format(datetimeFmt), EventTimeLoc: et.In(loc).Format(datetimeFmt),
} }
// 线程安全 // 线程安全
sdk.bufferChan <- log sdk.bufferChan <- log
} }
// 按服务器时区记录日志 // 按服务器时区记录日志
func (sdk *SDK) LogLtz(uid, event string, property map[string]any) { func (sdk *SDK) LogLtz(uid, event string, property map[string]any, customEventTime ...time.Time) {
sdk.Log(uid, event, property, time.Local.String()) sdk.Log(uid, event, property, time.Local.String(), customEventTime...)
}
// 用户属性初始化
func (sdk *SDK) Uinit(uid string, property map[string]any, timezone string, customEventTime ...time.Time) {
sdk.Log(uid, "u_init", property, timezone, customEventTime...)
}
func (sdk *SDK) UinitLtz(uid string, property map[string]any, customEventTime ...time.Time) {
sdk.Uinit(uid, property, time.Local.String(), customEventTime...)
}
// 用户属性设置
func (sdk *SDK) Uset(uid string, property map[string]any, timezone string, customEventTime ...time.Time) {
sdk.Log(uid, "u_set", property, timezone, customEventTime...)
}
func (sdk *SDK) UsetLtz(uid string, property map[string]any, customEventTime ...time.Time) {
sdk.Uset(uid, property, time.Local.String(), customEventTime...)
}
// 用户属性删除
func (sdk *SDK) Uunset(uid string, property map[string]any, timezone string, customEventTime ...time.Time) {
sdk.Log(uid, "u_unset", property, timezone, customEventTime...)
}
func (sdk *SDK) UunsetLtz(uid string, property map[string]any, customEventTime ...time.Time) {
sdk.Uunset(uid, property, time.Local.String(), customEventTime...)
}
// 用户属性自增/减
func (sdk *SDK) Uinc(uid string, property map[string]any, timezone string, customEventTime ...time.Time) {
sdk.Log(uid, "u_inc", property, timezone, customEventTime...)
}
func (sdk *SDK) UincLtz(uid string, property map[string]any, customEventTime ...time.Time) {
sdk.Uinc(uid, property, time.Local.String(), customEventTime...)
} }
// 这个方法只会在内部协程调用 // 这个方法只会在内部协程调用

View File

@@ -1,5 +1,6 @@
package honor package honor
const ( const (
Host = "https://iap-api.cloud.honor.com" Host = "https://iap-api-drcn.cloud.honor.com"
TokenHost = "https://hnoauth-login-drcn.cloud.honor.com"
) )

View File

@@ -9,19 +9,50 @@ import (
"encoding/base64" "encoding/base64"
"encoding/pem" "encoding/pem"
"errors" "errors"
"time"
"github.com/ayflying/utility_go/package/pay/common" "github.com/ayflying/utility_go/package/pay/common"
"github.com/ayflying/utility_go/pkg"
"github.com/gogf/gf/v2/frame/g"
) )
type Pay struct { type Pay struct {
PubKey string `json:"pubKey"` PubKey string `json:"pubKey"`
AppId string `json:"appId"` AppId string `json:"appId"`
ClientSecret string `json:"client_secret"`
} }
func New(pay *Pay) *Pay { func New(pay *Pay) *Pay {
return &Pay{ return pay
AppId: pay.AppId,
PubKey: pay.PubKey,
} }
func (p *Pay) GetToken(ctx context.Context) (accessToken string, err error) {
type TokenResp struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
TokenType string `json:"token_type"`
}
get, err := pkg.Cache("redis", "cache").GetOrSetFunc(ctx, "pay:honor:Sign:token", func(ctx context.Context) (value interface{}, err error) {
url := TokenHost + "/oauth2/v3/token"
get, err := g.Client().Post(ctx, url, g.Map{
"client_id": p.AppId,
"client_secret": p.ClientSecret,
"grant_type": "client_credentials",
})
//var res *TokenResp
//gjson.DecodeTo(get, &res)
value = get.ReadAllString()
return
}, time.Hour)
var res *TokenResp
err = get.Scan(&res)
accessToken = res.AccessToken
return
} }
// VerifyRSASignature 验证RSA数字签名 // VerifyRSASignature 验证RSA数字签名
@@ -29,13 +60,13 @@ func New(pay *Pay) *Pay {
// sign: 签名的Base64编码字符串 // sign: 签名的Base64编码字符串
// pubKey: PEM格式的公钥字符串 // pubKey: PEM格式的公钥字符串
// 返回验证结果和可能的错误 // 返回验证结果和可能的错误
func (p *Pay) VerifyRSASignature(ctx context.Context, data []byte, sign string) (bool, error) { func (p *Pay) VerifyRSASignature(ctx context.Context, data []byte, signature string) (bool, error) {
//req := g.RequestFromCtx(ctx).Request //req := g.RequestFromCtx(ctx).Request
//post, err := common.ParseNotifyToBodyMap(req) //post, err := common.ParseNotifyToBodyMap(req)
//var data = gjson.MustEncode(post) //var data = gjson.MustEncode(post)
// 解码Base64格式的签名 // 解码Base64格式的签名
signBytes, err := base64.StdEncoding.DecodeString(sign) signBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil { if err != nil {
return false, errors.New("签名解码失败: " + err.Error()) return false, errors.New("签名解码失败: " + err.Error())
} }

View File

@@ -1,11 +1,40 @@
package honor package honor
import ( import (
"errors"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/grand"
"net/http" "net/http"
) )
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
PurchaseProductInfo string `json:"purchaseProductInfo"`
DataSig string `json:"dataSig"`
SigAlgorithm string `json:"sigAlgorithm"`
} `json:"data"`
}
//// 响应结果结构体
//type Response struct {
// Code int `json:"code"` // 结果码 0: 成功,其他: 失败
// Message string `json:"message"` // 错误信息
// Data *DataContent `json:"data"` // 包含购买信息的结构体
//}
//
//// 数据内容结构体对应data字段
//type DataContent struct {
// PurchaseProductInfo string `json:"purchaseProductInfo"` // 消耗结果数据的JSON字符串
// DataSig string `json:"dataSig"` // purchaseProductInfo的签名
// SigAlgorithm string `json:"sigAlgorithm"` // 签名算法,云侧加密算法为"RSA"
//}
func (p *Pay) Notification(r *http.Request) { func (p *Pay) Notification(r *http.Request) {
} }
@@ -13,14 +42,33 @@ func (p *Pay) Notification(r *http.Request) {
// ConsumeProduct 商品消耗 // ConsumeProduct 商品消耗
func (p *Pay) ConsumeProduct(purchaseToken string) (err error) { func (p *Pay) ConsumeProduct(purchaseToken string) (err error) {
url := Host + "/iap/server/consumeProduct" url := Host + "/iap/server/consumeProduct"
_, err = g.Client().ContentJson().Post(gctx.New(), url, g.Map{ //获取token
"purchaseToken": purchaseToken, token, err := p.GetToken(gctx.New())
"developerChallenge": "",
})
if err != nil { if err != nil {
return return
} }
var header = g.MapStrStr{
"access-token": token,
"x-iap-appid": p.AppId,
"purchaseToken": purchaseToken,
}
var params = g.Map{
"purchaseToken": purchaseToken,
"developerChallenge": grand.S(16),
}
get := g.Client().ContentJson().Header(header).PostContent(gctx.New(), url, params)
g.Log().Debugf(gctx.New(), "商品消耗请求发送:url=%v, header=%v, params=%v", url, header, params)
g.Log().Debugf(gctx.New(), "商品消耗请求收到回复: %s", get)
var res *Response
err = gjson.DecodeTo(get, &res)
if err != nil {
return
}
if res.Code != 0 {
g.Log().Error(gctx.New(), "商品消耗失败: "+res.Message)
return errors.New(res.Message)
}
return return
} }