574 lines
18 KiB
Go
574 lines
18 KiB
Go
package activityser
|
||
|
||
import (
|
||
"context"
|
||
"crypto/hmac"
|
||
"crypto/rand"
|
||
"crypto/sha256"
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"encoding/json"
|
||
"fmt"
|
||
"time"
|
||
|
||
"91porn-server/app/appg"
|
||
"91porn-server/app/proto"
|
||
"91porn-server/app/service/activityclient"
|
||
"91porn-server/app/service/customerser"
|
||
"91porn-server/app/service/productser"
|
||
"91porn-server/app/service/rechargeser"
|
||
"91porn-server/common"
|
||
"91porn-server/common/constant"
|
||
"91porn-server/common/crypt"
|
||
"91porn-server/common/log"
|
||
"91porn-server/common/rchgutil"
|
||
"91porn-server/common/stderr"
|
||
"91porn-server/middleware/ua"
|
||
"91porn-server/models/commod"
|
||
"91porn-server/models/v/advanceordermod"
|
||
"91porn-server/models/v/currencymod"
|
||
"91porn-server/models/v/productmod"
|
||
"91porn-server/models/v/rchgamtmod"
|
||
"91porn-server/models/v/sourcemod"
|
||
"91porn-server/models/v/usermod"
|
||
"91porn-server/models/v/walletmod"
|
||
|
||
"go.mongodb.org/mongo-driver/bson"
|
||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
)
|
||
|
||
// PayChannel 支付渠道(精简字段)
|
||
type PayChannel struct {
|
||
Type string `json:"type"`
|
||
TypeName string `json:"typeName"`
|
||
}
|
||
|
||
// ActivityCurrencyItem 活动服金币充值列表项
|
||
type ActivityCurrencyItem struct {
|
||
ID primitive.ObjectID `json:"id"`
|
||
Coin int64 `json:"coin"`
|
||
Money int64 `json:"money"`
|
||
Name string `json:"typeName"`
|
||
GiveCoin int64 `json:"giveCoin"`
|
||
RechargeType []PayChannel `json:"rechargeType"`
|
||
}
|
||
|
||
func toPayChannels(src []rchgamtmod.PayChannelRes) []PayChannel {
|
||
channels := make([]PayChannel, 0, len(src))
|
||
for _, ch := range src {
|
||
channels = append(channels, PayChannel{
|
||
Type: ch.Type,
|
||
TypeName: ch.TypeName,
|
||
})
|
||
}
|
||
return channels
|
||
}
|
||
|
||
// GetCurrencyList 获取金币充值列表
|
||
func GetCurrencyList(ctx context.Context) ([]*ActivityCurrencyItem, stderr.Code) {
|
||
currencys, err := currencymod.List(commod.Gold)
|
||
if err != nil {
|
||
log.ErrorX(ctx, "活动服-获取金币列表异常", log.E(err))
|
||
return nil, stderr.ErrNetWorkBusy
|
||
}
|
||
|
||
removeRepeat := make(map[int64]struct{})
|
||
var moneys []string
|
||
for _, cur := range currencys {
|
||
if _, ok := removeRepeat[cur.Price]; ok {
|
||
continue
|
||
}
|
||
removeRepeat[cur.Price] = struct{}{}
|
||
moneys = append(moneys, rechargeser.FenToYuan(cur.Price))
|
||
}
|
||
|
||
payReq := rchgutil.GainPayTypeReq{Money: moneys}
|
||
bc, err := payReq.GetPayType()
|
||
if err != nil {
|
||
log.ErrorX(ctx, "活动服-获取支付通道列表异常", log.E(err))
|
||
return nil, stderr.ErrNetWorkBusy
|
||
}
|
||
|
||
data := make([]*ActivityCurrencyItem, 0, len(currencys))
|
||
for _, v := range currencys {
|
||
if v.Price < 100 {
|
||
continue
|
||
}
|
||
rechargeType := rechargeser.GetPayChannelDetails_New(v.Price, bc, 0)
|
||
if len(rechargeType) <= 0 {
|
||
continue
|
||
}
|
||
data = append(data, &ActivityCurrencyItem{
|
||
ID: v.ID,
|
||
Coin: v.Coins,
|
||
Money: v.Price,
|
||
Name: v.Name,
|
||
GiveCoin: v.GiveGold,
|
||
RechargeType: toPayChannels(rechargeType),
|
||
})
|
||
}
|
||
return data, stderr.Success
|
||
}
|
||
|
||
// CardCategory 会员卡分类
|
||
type CardCategory int
|
||
|
||
const (
|
||
DefaultCard CardCategory = 0
|
||
PreSaleCard CardCategory = 1
|
||
NewbieCard CardCategory = 2
|
||
)
|
||
|
||
// VipCardInfo 活动服会员卡信息
|
||
type VipCardInfo struct {
|
||
Id string `json:"id"`
|
||
Category CardCategory `json:"category"`
|
||
VipGrade string `json:"vipGrade"`
|
||
Name string `json:"name"`
|
||
Desc string `json:"desc"`
|
||
PreMoney int64 `json:"preMoney"`
|
||
Money int64 `json:"money"`
|
||
CanUseCoin bool `json:"canUseCoin"`
|
||
DayCount int64 `json:"dayCount"`
|
||
GiveCoin int64 `json:"giveCoin"`
|
||
Sort int32 `json:"sort"`
|
||
Image string `json:"image"`
|
||
Rights []RightInfo `json:"rights"`
|
||
RechargeType []PayChannel `json:"rechargeType"`
|
||
ActivityStartAt time.Time `json:"activityStartAt"`
|
||
ActivityEndAt time.Time `json:"activityEndAt"`
|
||
CanUpgrade bool `json:"canUpgrade"`
|
||
PreSaleStep int `json:"preSaleStep"` // 预售卡阶段 0-预付阶段 1-尾款阶段 2-尾款付款完成(结束)
|
||
}
|
||
|
||
// RightInfo 权益信息
|
||
type RightInfo struct {
|
||
Name string `json:"name"`
|
||
Desc string `json:"desc"`
|
||
Image string `json:"image"`
|
||
}
|
||
|
||
// VipDeduct 会员卡当前可用抵扣(vip/list 按抵扣后金额匹配支付通道用)
|
||
type VipDeduct struct {
|
||
ProductID string // 会员卡ID
|
||
DeductAmount int64 // 券面额(分)
|
||
}
|
||
|
||
// GetProductList 获取会员卡列表。
|
||
// deducts 非空时,对携带抵扣的普通会员卡按"抵扣后有效金额"重新匹配支付通道(rechargeType),
|
||
// money/preMoney 仍返回原价(避免与下单预览重复扣减)。
|
||
func GetProductList(ctx context.Context, uid uint64, deducts []VipDeduct) ([]VipCardInfo, error) {
|
||
u, err := usermod.FindUserByUID(uid)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("查询用户异常: %w", err)
|
||
}
|
||
if u == nil {
|
||
return nil, fmt.Errorf("用户不存在: %d", uid)
|
||
}
|
||
|
||
productList, err := rechargeser.New_ProductList(uid, u.SysType, true, 0)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 抵扣券:按抵扣后有效金额预匹配支付通道(命中的卡覆盖 rechargeType)
|
||
deductedChans := buildDeductedRechargeTypes(productList, deducts)
|
||
|
||
var cards []VipCardInfo
|
||
for _, group := range productList {
|
||
for _, item := range group.List {
|
||
p := item.Product
|
||
card := VipCardInfo{
|
||
Id: p.ID.Hex(),
|
||
VipGrade: fmt.Sprintf("%d", p.VipLevel),
|
||
Name: p.Name,
|
||
Desc: p.Desc,
|
||
PreMoney: p.OriginalPrice * 10,
|
||
Money: p.DiscountedPrice * 10,
|
||
CanUseCoin: p.IsAmountPay,
|
||
DayCount: int64(p.Duration),
|
||
GiveCoin: p.GiveCoin,
|
||
Sort: int32(p.Sort),
|
||
Image: p.BGImg,
|
||
CanUpgrade: p.IsUpgrade,
|
||
}
|
||
|
||
switch p.ProductType {
|
||
case commod.AdvanceCard:
|
||
card.Category = PreSaleCard
|
||
advOrder, _ := advanceordermod.IsExist(bson.M{"productID": p.ID, "uid": uid})
|
||
// advOrder.Status 取值(advanceordermod):
|
||
// 0 DEFAULT / 1 AdvanceProcessing(预付中) / 2 AdvanceSUCCESS(预付成功)
|
||
// 3 BalanceProcessing(尾款中) / 4 BalanceSUCCESS(尾款成功)
|
||
if advOrder == nil || advOrder.Status == advanceordermod.DEFAULT || advOrder.Status == advanceordermod.AdvanceProcessing {
|
||
// 预付阶段:尚未下单 / 预付中
|
||
card.PreSaleStep = 0
|
||
card.ActivityStartAt = p.ActivityTime
|
||
card.ActivityEndAt = p.EndTime
|
||
card.Money = p.AdvanceAmount * 10
|
||
} else if advOrder.Status == advanceordermod.AdvanceSUCCESS || advOrder.Status == advanceordermod.BalanceProcessing {
|
||
// 尾款阶段:预付成功 / 尾款支付中
|
||
card.PreSaleStep = 1
|
||
card.ActivityStartAt = p.StartTime
|
||
card.ActivityEndAt = p.EndTime
|
||
card.Money = p.BalanceAmount * 10
|
||
card.Image = p.NewBgImg
|
||
} else if advOrder.Status == advanceordermod.BalanceSUCCESS {
|
||
// 尾款付款完成(结束)
|
||
card.PreSaleStep = 2
|
||
}
|
||
case commod.NEWUSERCard:
|
||
card.Category = NewbieCard
|
||
card.ActivityStartAt = u.CreatedAt
|
||
card.ActivityEndAt = card.ActivityStartAt.Add(time.Duration(p.ShowCountdownTime) * time.Hour)
|
||
if time.Now().After(card.ActivityEndAt) {
|
||
continue
|
||
}
|
||
default:
|
||
card.Category = DefaultCard
|
||
}
|
||
|
||
if card.Image == "" {
|
||
card.Image = p.BGImg
|
||
}
|
||
|
||
rights := make([]RightInfo, 0, len(p.NewPrivilege))
|
||
for _, pr := range p.NewPrivilege {
|
||
rights = append(rights, RightInfo{
|
||
Name: pr.Name,
|
||
Desc: pr.Desc,
|
||
Image: pr.Image,
|
||
})
|
||
}
|
||
card.Rights = rights
|
||
card.RechargeType = toPayChannels(item.RechargeType)
|
||
// 抵扣券:按抵扣后金额匹配的支付通道覆盖原价通道
|
||
if chans, ok := deductedChans[p.ID.Hex()]; ok {
|
||
card.RechargeType = chans
|
||
}
|
||
|
||
cards = append(cards, card)
|
||
}
|
||
}
|
||
return cards, nil
|
||
}
|
||
|
||
// minDeductPayFen 抵扣后最低实付(分),与下单折价封顶保持一致
|
||
const minDeductPayFen = 1
|
||
|
||
// buildDeductedRechargeTypes 依据 deducts 计算各会员卡"抵扣后有效金额"对应的支付通道。
|
||
// 支付通道按支付金额匹配(如微信要求达标金额),券抵扣后实付变小可能改变可用通道,
|
||
// 故对携带抵扣的普通会员卡(非预售卡)按 min(券面额, 原价-最低实付) 折后金额重新匹配 rechargeType。
|
||
// 返回 productIdHex -> 支付通道;deducts 为空或无命中时返回 nil,调用方保留原价通道。
|
||
func buildDeductedRechargeTypes(productList []proto.ProductList, deducts []VipDeduct) map[string][]PayChannel {
|
||
deductMap := make(map[string]int64, len(deducts))
|
||
for _, d := range deducts {
|
||
if d.ProductID != "" && d.DeductAmount > 0 {
|
||
deductMap[d.ProductID] = d.DeductAmount
|
||
}
|
||
}
|
||
if len(deductMap) == 0 {
|
||
return nil
|
||
}
|
||
|
||
type effEntry struct {
|
||
hex string
|
||
effFen int64
|
||
}
|
||
var entries []effEntry
|
||
moneySet := make(map[string]struct{})
|
||
var moneys []string
|
||
for _, group := range productList {
|
||
for _, item := range group.List {
|
||
p := item.Product
|
||
if p.ProductType == commod.AdvanceCard {
|
||
continue // 预售卡分阶段付款,不参与抵扣
|
||
}
|
||
deduct, ok := deductMap[p.ID.Hex()]
|
||
if !ok {
|
||
continue
|
||
}
|
||
originFen := p.DiscountedPrice * 10
|
||
maxDeduct := originFen - minDeductPayFen
|
||
if maxDeduct <= 0 {
|
||
continue
|
||
}
|
||
if deduct > maxDeduct {
|
||
deduct = maxDeduct
|
||
}
|
||
effFen := originFen - deduct
|
||
entries = append(entries, effEntry{hex: p.ID.Hex(), effFen: effFen})
|
||
y := rechargeser.FenToYuan(effFen)
|
||
if _, exist := moneySet[y]; !exist {
|
||
moneySet[y] = struct{}{}
|
||
moneys = append(moneys, y)
|
||
}
|
||
}
|
||
}
|
||
if len(entries) == 0 {
|
||
return nil
|
||
}
|
||
|
||
bc, err := (&rchgutil.GainPayTypeReq{Money: moneys}).GetPayTypeFromCache()
|
||
if err != nil {
|
||
log.Warn("活动服-抵扣后支付通道查询失败", log.Any("moneys", moneys), log.E(err))
|
||
}
|
||
out := make(map[string][]PayChannel, len(entries))
|
||
for _, e := range entries {
|
||
out[e.hex] = toPayChannels(rechargeser.GetPayChannelDetails_New(e.effFen, bc, 0))
|
||
}
|
||
return out
|
||
}
|
||
|
||
// UserBalance 用户余额信息
|
||
type UserBalance struct {
|
||
Gold int64 `json:"gold"` // 金币余额
|
||
Integral int64 `json:"integral"` // 积分余额
|
||
LotteryFreeTimes int64 `json:"lotteryFreeTimes"` // 抽奖免费次数
|
||
VipLevel int `json:"vipLevel,omitempty"` // VIP 等级;用户未开通或已过期时不下发
|
||
VipExpireDate time.Time `json:"vipExpireDate,omitempty"` // VIP 截止时间;用户未开通或已过期时不下发
|
||
PromotionCode string `json:"promotionCode,omitempty"` // 邀请码
|
||
PromoteURL string `json:"promoteURL,omitempty"` // 邀请链接(已拼好 PromotionField + 邀请码)
|
||
}
|
||
|
||
// GetUserBalance 获取用户金币/积分余额及 VIP 信息(VIP 已过期时不下发 VIP 字段)
|
||
func GetUserBalance(uid uint64) (*UserBalance, error) {
|
||
w, err := walletmod.GetWallet(uid)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("查询钱包异常: %w", err)
|
||
}
|
||
res := &UserBalance{}
|
||
if w != nil {
|
||
res.Gold = w.Amount
|
||
res.Integral = w.Integral
|
||
res.LotteryFreeTimes = w.LotteryTimes
|
||
}
|
||
// 用户信息独立取数,单点失败不影响余额下发
|
||
u, uerr := usermod.FindUserByUID(uid)
|
||
if uerr != nil {
|
||
log.Warn("活动服-查询用户信息失败", log.Any("uid", uid), log.E(uerr))
|
||
return res, nil
|
||
}
|
||
if u == nil {
|
||
return res, nil
|
||
}
|
||
if u.IsVIP(time.Now()) {
|
||
res.VipLevel = u.VipLevel
|
||
res.VipExpireDate = u.VipExpireDate
|
||
}
|
||
// 邀请码 + 邀请链接(与 /api/app/mine/info 的 promoteURL 拼接方式一致)
|
||
res.PromotionCode = u.PromCode
|
||
if base := sourcemod.GetRandomPromotionURL(); base != "" && u.PromCode != "" {
|
||
res.PromoteURL = common.BindUrl(base, constant.PromotionField+u.PromCode)
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
func convertBuyType(actBuyType int) commod.BuyType {
|
||
switch actBuyType {
|
||
case 1:
|
||
return commod.BuyGold
|
||
case 2:
|
||
return commod.BuyProduct
|
||
default:
|
||
return commod.BuyType(actBuyType)
|
||
}
|
||
}
|
||
|
||
type RechargeAttribution struct {
|
||
ActivityID string
|
||
ExperimentID string
|
||
ExperimentVariant string
|
||
SessionID string
|
||
}
|
||
|
||
// CreateRechargeOrder 创建充值订单。活动入口的 sourcePage 由服务端固定,
|
||
// 避免调用方伪造其他来源;其余实验字段仍走统一下单校验。
|
||
func CreateRechargeOrder(
|
||
ctx context.Context,
|
||
uid uint64,
|
||
rechargeType, productID string,
|
||
buyType int,
|
||
ip string,
|
||
attribution RechargeAttribution,
|
||
couponID string,
|
||
deductAmount int64,
|
||
) (payUrl, mode string, err error) {
|
||
pid, err := primitive.ObjectIDFromHex(productID)
|
||
if err != nil {
|
||
return "", "", fmt.Errorf("invalid productId: %w", err)
|
||
}
|
||
|
||
u, err := usermod.FindUserByUID(uid)
|
||
if err != nil {
|
||
return "", "", fmt.Errorf("查询用户异常: %w", err)
|
||
}
|
||
if u == nil {
|
||
return "", "", fmt.Errorf("用户不存在: %d", uid)
|
||
}
|
||
|
||
realBuyType := convertBuyType(buyType)
|
||
|
||
in := &rechargeser.RechargeRequest{
|
||
UID: uid,
|
||
IP: ip,
|
||
RechargeType: rechargeType,
|
||
ProductID: pid,
|
||
BuyType: realBuyType,
|
||
SourcePage: rechargeser.OrderSourcePageH5Activity,
|
||
SourceRef: attribution.ActivityID,
|
||
ActivityID: attribution.ActivityID,
|
||
ExperimentID: attribution.ExperimentID,
|
||
ExperimentVariant: attribution.ExperimentVariant,
|
||
SessionID: attribution.SessionID,
|
||
}
|
||
// 抵扣券作为活动服附加对象单独传入,不混入客户端下单请求体
|
||
var deduct *rechargeser.ActivityDeduct
|
||
if couponID != "" && deductAmount > 0 {
|
||
deduct = &rechargeser.ActivityDeduct{CouponID: couponID, DeductAmount: deductAmount}
|
||
}
|
||
return rechargeser.Recharge(ctx, in, ua.UA{SysType: u.SysType}, deduct)
|
||
}
|
||
|
||
// BuyCoinProduct 金币购买商品
|
||
func BuyCoinProduct(ctx context.Context, uid uint64, productID string, sysType string) (stderr.Code, error) {
|
||
pid, err := primitive.ObjectIDFromHex(productID)
|
||
if err != nil {
|
||
return stderr.ErrParamError, fmt.Errorf("invalid productId: %w", err)
|
||
}
|
||
|
||
p, err := productmod.FindProduct(pid, sysType)
|
||
if err != nil || p == nil {
|
||
return stderr.ErrParamError, fmt.Errorf("商品不存在: %s", productID)
|
||
}
|
||
|
||
if !p.IsAmountPay {
|
||
return stderr.ErrParamError, fmt.Errorf("该商品不支持金币购买")
|
||
}
|
||
|
||
code := productser.Buy(uid, p.ProductType, pid, primitive.NilObjectID, primitive.NilObjectID, 0, "", sysType, "", 0, false, ua.UA{SysType: sysType}, "", productser.VIPExperimentAttribution{})
|
||
if code != stderr.Success {
|
||
return code, fmt.Errorf("购买失败")
|
||
}
|
||
return stderr.Success, nil
|
||
}
|
||
|
||
// GenerateSecretKey 生成 AES-256 密钥
|
||
func GenerateSecretKey() (string, error) {
|
||
key := make([]byte, 32)
|
||
if _, err := rand.Read(key); err != nil {
|
||
return "", err
|
||
}
|
||
return base64.StdEncoding.EncodeToString(key), nil
|
||
}
|
||
|
||
// DecryptSign AES-CBC 解密签名载荷
|
||
func DecryptSign(secretKeyBase64 string, signBase64 string) (*activityclient.SignPayload, error) {
|
||
secretKey, err := base64.StdEncoding.DecodeString(secretKeyBase64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("decode secretKey failed: %w", err)
|
||
}
|
||
signBytes, err := base64.URLEncoding.DecodeString(signBase64)
|
||
if err != nil {
|
||
signBytes, err = base64.StdEncoding.DecodeString(signBase64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("decode sign failed: %w", err)
|
||
}
|
||
}
|
||
plaintext, err := crypt.CoreAesDecrypt(signBytes, string(secretKey))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("decrypt sign failed: %w", err)
|
||
}
|
||
var payload activityclient.SignPayload
|
||
if err := json.Unmarshal([]byte(plaintext), &payload); err != nil {
|
||
return nil, fmt.Errorf("parse sign payload failed: %w", err)
|
||
}
|
||
return &payload, nil
|
||
}
|
||
|
||
// HmacSHA256 用于回调签名
|
||
func HmacSHA256(secretKeyBase64 string, data []byte) (string, error) {
|
||
keyBytes, err := base64.StdEncoding.DecodeString(secretKeyBase64)
|
||
if err != nil {
|
||
return "", fmt.Errorf("decode secretKey failed: %w", err)
|
||
}
|
||
h := hmac.New(sha256.New, keyBytes)
|
||
h.Write(data)
|
||
return hex.EncodeToString(h.Sum(nil)), nil
|
||
}
|
||
|
||
// BuildSignedURL 生成带 sign 的活动服请求 URL
|
||
func BuildSignedURL(userId, nickname, avatar string) (signedURL, sign string, err error) {
|
||
conf := appg.Conf.ActivityServer
|
||
baseURL := activityclient.GetActivityDomain()
|
||
if baseURL == "" {
|
||
return "", "", fmt.Errorf("活动服域名未获取,请检查配置")
|
||
}
|
||
|
||
now := time.Now()
|
||
payload := &activityclient.SignPayload{
|
||
AppId: conf.AppId,
|
||
UserId: userId,
|
||
Nickname: nickname,
|
||
Avatar: avatar,
|
||
Ts: now.Unix(),
|
||
}
|
||
|
||
sign, err = activityclient.EncryptSign(conf.SecretKey, payload)
|
||
if err != nil {
|
||
return "", "", fmt.Errorf("encrypt sign failed: %w", err)
|
||
}
|
||
|
||
signedURL = fmt.Sprintf("%s?appId=%s&sign=%s", baseURL, conf.AppId, sign)
|
||
return signedURL, sign, nil
|
||
}
|
||
|
||
// AppInfoResp 应用信息
|
||
type AppInfoResp struct {
|
||
CustomerServiceUrl string `json:"customerServiceUrl"`
|
||
}
|
||
|
||
// GetAppInfo 获取应用信息
|
||
func GetAppInfo(ctx context.Context, uid uint64) (*AppInfoResp, error) {
|
||
resp, err := customerser.GetUrl(uid, ua.UA{})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("获取客服地址失败: %w", err)
|
||
}
|
||
return &AppInfoResp{
|
||
CustomerServiceUrl: resp.Data.Url,
|
||
}, nil
|
||
}
|
||
|
||
// BuildLoginCurl 生成活动服登录接口的 curl 命令(调试用)
|
||
func BuildLoginCurl(userId, nickname, avatar string) (string, error) {
|
||
conf := appg.Conf.ActivityServer
|
||
activityHost := activityclient.GetActivityDomain()
|
||
if activityHost == "" {
|
||
return "", fmt.Errorf("活动服域名未获取,请检查配置")
|
||
}
|
||
|
||
now := time.Now()
|
||
payload := &activityclient.SignPayload{
|
||
AppId: conf.AppId,
|
||
UserId: userId,
|
||
Nickname: nickname,
|
||
Avatar: avatar,
|
||
Ts: now.Unix(),
|
||
}
|
||
|
||
sign, err := activityclient.EncryptSign(conf.SecretKey, payload)
|
||
if err != nil {
|
||
return "", fmt.Errorf("encrypt sign failed: %w", err)
|
||
}
|
||
|
||
payloadJSON, _ := json.MarshalIndent(payload, "", " ")
|
||
|
||
result := fmt.Sprintf("AppId: %s\nSecretKey: %s\n\n", conf.AppId, conf.SecretKey)
|
||
result += fmt.Sprintf("--- Generated Sign ---\nsign: %s\n\n", sign)
|
||
result += fmt.Sprintf("payload: %s\n\n", string(payloadJSON))
|
||
result += fmt.Sprintf("--- CURL ---\ncurl -X POST '%s/api/app/index/login' \\\n -H 'Content-Type: application/json' \\\n -d '{\"appId\":\"%s\",\"sign\":\"%s\"}'",
|
||
activityHost, conf.AppId, sign)
|
||
|
||
return result, nil
|
||
}
|