Compare commits

..

6 Commits

Author SHA1 Message Date
zhx
bb79845b6b 游戏机器人 2026-06-16 20:47:26 +08:00
zhx
83b82b8e30 配置 2026-06-16 17:14:34 +08:00
zhx
11d2388449 Merge branch 'test' 2026-06-16 17:12:14 +08:00
zhx
a7fb47579d fix: persist room rps config 2026-06-16 14:54:57 +08:00
zhx
0f767a0f22 fix: avoid animated room rps gift icons 2026-06-16 14:54:57 +08:00
zhx
9a9cccd194 fix: split room rps gift media urls 2026-06-16 14:54:57 +08:00
5 changed files with 147 additions and 30 deletions

View File

@ -2,8 +2,10 @@ package gamemanagement
import (
"context"
"crypto/rand"
"database/sql"
"fmt"
"math/big"
"net/url"
"strings"
"unicode/utf8"
@ -12,6 +14,7 @@ import (
type RobotProfile struct {
Nickname string
Avatar string
Gender string
}
type RobotProfileSource interface {
@ -29,7 +32,7 @@ func NewLikeiRobotProfileSource(db *sql.DB) RobotProfileSource {
return &likeiRobotProfileSource{db: db}
}
// WithRobotProfileSource 注入机器人资料池;创建机器人时只消费这里返回的线上 likei 用户昵称和头像
// WithRobotProfileSource 注入机器人资料池;创建机器人优先消费线上 likei 用户昵称和头像,未配置时再走本地随机资料兜底
func WithRobotProfileSource(source RobotProfileSource) Option {
return func(h *Handler) {
h.robotProfiles = source
@ -81,6 +84,50 @@ func (s *likeiRobotProfileSource) RandomRobotProfiles(ctx context.Context, count
return profiles, nil
}
func robotProfilesForGenerate(ctx context.Context, source RobotProfileSource, count int) ([]RobotProfile, error) {
if source != nil {
// 已配置 likei 时继续使用真实资料池;查询失败不能静默降级,否则线上数据源故障会被批量造号掩盖。
return source.RandomRobotProfiles(ctx, count)
}
profiles := make([]RobotProfile, 0, count)
for index := 0; index < count; index++ {
profiles = append(profiles, randomRobotProfile())
}
return profiles, nil
}
func randomRobotProfile() RobotProfile {
seed := randomRobotHex(8)
nameSeed := randomRobotHex(3)
if seed == "fallback" {
seed = fmt.Sprintf("fallback-%d", randomRobotInt(1000000))
}
// 本地随机头像只保存绝对 URL不在 admin-server 里下载或转存图片user-service 仍负责资料字段校验。
return RobotProfile{
Nickname: fmt.Sprintf("Robot %s", strings.ToUpper(nameSeed)),
Avatar: "https://api.dicebear.com/9.x/adventurer/png?seed=hyapp-robot-" + url.QueryEscape(seed),
Gender: randomRobotGender(),
}
}
func randomRobotGender() string {
if randomRobotInt(2) == 0 {
return "male"
}
return "female"
}
func randomRobotInt(max int64) int64 {
if max <= 0 {
return 0
}
value, err := rand.Int(rand.Reader, big.NewInt(max))
if err != nil {
return 0
}
return value.Int64()
}
func normalizeRobotProfile(profile RobotProfile) (RobotProfile, bool) {
profile.Nickname = strings.TrimSpace(profile.Nickname)
profile.Avatar = strings.TrimSpace(profile.Avatar)

View File

@ -5,6 +5,7 @@ import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"hyapp-admin-server/internal/integration/gameclient"
@ -104,3 +105,46 @@ func TestGenerateDiceRobotsUsesLikeiProfiles(t *testing.T) {
t.Fatalf("registered user ids = %#v", games.registered)
}
}
func TestGenerateDiceRobotsFallsBackToRandomProfilesWhenLikeiMissing(t *testing.T) {
gin.SetMode(gin.TestMode)
users := &fakeRobotUserClient{}
games := &fakeRobotGameClient{}
handler := New(games, users, nil)
recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)
c.Set(middleware.ContextRequestID, "req-robot-random")
c.Set(middleware.ContextUserID, uint(7))
c.Request = httptest.NewRequest(http.MethodPost, "/api/v1/admin/games/self/dice/robots:generate", bytes.NewBufferString(`{
"count": 3,
"country": "TH"
}`))
c.Request.Header.Set("Content-Type", "application/json")
handler.GenerateDiceRobots(c)
if recorder.Code != http.StatusOK {
t.Fatalf("status = %d, body = %s", recorder.Code, recorder.Body.String())
}
if len(users.created) != 3 {
t.Fatalf("created users = %d, want 3", len(users.created))
}
for index, created := range users.created {
if !strings.HasPrefix(created.Username, "Robot ") {
t.Fatalf("created[%d] username should be generated, got %#v", index, created)
}
if !strings.HasPrefix(created.Avatar, "https://api.dicebear.com/9.x/adventurer/png?seed=hyapp-robot-") {
t.Fatalf("created[%d] avatar should be generated, got %#v", index, created)
}
if created.Gender != "male" && created.Gender != "female" {
t.Fatalf("created[%d] gender should be random male/female, got %#v", index, created)
}
if created.Country != "TH" || created.Source != "game_robot" {
t.Fatalf("created[%d] metadata = %#v", index, created)
}
}
if len(games.registered) != 3 || games.registered[0] != 9001 || games.registered[2] != 9003 {
t.Fatalf("registered user ids = %#v", games.registered)
}
}

View File

@ -220,19 +220,14 @@ func (h *Handler) GenerateDiceRobots(c *gin.Context) {
if country == "" {
country = "SA"
}
if h.robotProfiles == nil {
response.ServerError(c, "likei 机器人资料源未配置")
return
}
// 新机器人资料只从 likei 线上用户库随机抽取;后台不再使用本地昵称池、随机头像站或 COS 转存,
// 这样每次批量创建都面对真实用户资料池,避免少量固定预设反复出现在匹配列表里。
profiles, err := h.robotProfiles.RandomRobotProfiles(c.Request.Context(), int(req.Count))
// likei 是优先资料源;测试服或本地未配置时用随机资料兜底,避免运维为了造机器人账号被外部历史库阻塞。
profiles, err := robotProfilesForGenerate(c.Request.Context(), h.robotProfiles, int(req.Count))
if err != nil {
response.BadRequest(c, "获取 likei 机器人资料失败: "+err.Error())
response.BadRequest(c, "获取机器人资料失败: "+err.Error())
return
}
if len(profiles) < int(req.Count) {
response.BadRequest(c, "likei 机器人资料数量不足")
response.BadRequest(c, "机器人资料数量不足")
return
}
userIDs := make([]int64, 0, req.Count)
@ -240,13 +235,21 @@ func (h *Handler) GenerateDiceRobots(c *gin.Context) {
accountLanguage := robotAccountLanguage(req.NicknameLanguage)
for index := int32(0); index < req.Count; index++ {
profile := profiles[index]
gender := strings.TrimSpace(req.Gender)
if gender == "" {
gender = strings.TrimSpace(profile.Gender)
}
if gender == "" {
// likei 当前只提供昵称和头像;没有显式性别时保持旧的均匀分布,随机兜底资料会在 profile 中给出真实随机值。
gender = robotGender(int(index), "")
}
created, err := h.user.QuickCreateAccount(c.Request.Context(), userclient.QuickCreateAccountRequest{
RequestID: requestID,
Caller: "admin-server",
Password: randomRobotPassword(),
Username: profile.Nickname,
Avatar: profile.Avatar,
Gender: robotGender(int(index), req.Gender),
Gender: gender,
Country: country,
DeviceID: "game-robot-" + randomRobotHex(8),
Source: "game_robot",

View File

@ -51,22 +51,34 @@ google_play:
token_url: "https://oauth2.googleapis.com/token"
http_timeout: "10s"
consume_enabled: true
mifapay:
# MiFaPay 是 H5 统一三方支付入口;商家公钥只用于记录商户侧配置,真实下单签名必须继续使用商户私钥。
enabled: true
mer_account: "6000055d34f445418124ab7c0beb81a6"
mer_no: "10001910"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVDVrlVS+HkfLx+56v1Fyfqj5Gd+DRkPIK4EOu+SMi+wtP4dwPBeXkrL1w+nSC0UFQ2Py690qdRu1FCSTNMWC8kfzddC4xlckJKXa9NoDyeJIN/Z5Za9Fg2znfqTee9BE8NnJk4EtmRwKJQaP8sCrYsIDv/bagywM9t25lKn2bmUOZKVVUtn/Xf5OBYDE6AVHB83J+HxX5VPLie+dbRdsRR+hoZs/vzLTNlZsTcrAnWUf7cqd9XNr39gXnXgdw61kzAC9RtSLbRPAo474F03xmLZKsL70vmBgex9/paljPxNnFVq1CPxmam5yzY0NtS6iXUlU7ttqAzBolSwPWla7QIDAQAB"
private_key: ""
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Kt1qR5jwf4xUVHqo2pLZW2Xb43P9c8BjMHeq4ih+u+8Qr5YtJa2EPv/sNoAQktjaUhsg9tJvtn1Pc46xIo3XeZiicdn91eNSdC6mZ8NxT6IJyyEr5x15o6hJORkiDbYg8k3rf40bZl8B6Oz6pEGPIYrmO8DVWN0Ak7qmWhHF5ePKusfLjy4TWEt2JmQGHAz+lfkDGaQzwtrC2kt4adYwcdpY78B4fH8Ssofr2fLuMQYl2QYWIV0lplAQicuTRhgWj4tora/MoK/LbKKFCthrElGvVJtial1QCfhOOUVgdjzGKdmuer8qiuseDraVIKYkAjuY9fGBWF+2N7mNIWOKwIDAQAB"
api_base_url: "https://platformtest.xqdmipay.com"
http_timeout: "10s"
environment: "test" # 可选值test/prod切换环境时必须保证后台商户公钥和本地私钥是一对。
environment_test:
mer_account: "d00f5fc97a114a0db291eceaf9841739"
mer_no: "10001925"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7FsuU9HXVXuFMKMbz10Hq0B3JfOkPJZwUfEUTdST3UuHpkp90LVLCoYfHJ8W9tV1HUhvZ+taTWrPY82vL5KPkyKok/M64NCRR3Gf/dojm6W+/ajylBhkQYiR/aksXCVTbjgt8eAbWCHpsoqqji0ZjdVZM/br6yHz89mm3nWK3GMPheRjwC2LROUdqOkpb2H3C4PKEm/zGBW0/88uSDIUzsoKwyMOhMyJuXqI+HMpMG3SNT732f4SllJrrF/reRJnok87LqBPOTCfAVeEwgWhk0PD6sktdISarqnVgYqfGBpAS+AmqhaNforZ6UTdNFDBMithau+6f/qC3+rr3YiiwQIDAQAB"
private_key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDsWy5T0ddVe4UwoxvPXQerQHcl86Q8lnBR8RRN1JPdS4emSn3QtUsKhh8cnxb21XUdSG9n61pNas9jza8vko+TIqiT8zrg0JFHcZ/92iObpb79qPKUGGRBiJH9qSxcJVNuOC3x4BtYIemyiqqOLRmN1Vkz9uvrIfPz2abedYrcYw+F5GPALYtE5R2o6SlvYfcLg8oSb/MYFbT/zy5IMhTOygrDIw6EzIm5eoj4cykwbdI1PvfZ/hKWUmusX+t5EmeiTzsuoE85MJ8BV4TCBaGTQ8PqyS10hJquqdWBip8YGkBL4CaqFo1+itnpRN00UMEyK2Fq77p/+oLf6uvdiKLBAgMBAAECggEALvaXJ/SEEuouNtHSDsvvYCm5AwN8WMWTn9SFMknQ76G4XGRkx3meZYLs36UEzRrw4FaqPD3ZfZSBjNUrwAohGR1D3dHwmwcWNtnu7mPPu3edkY1mVeLa2OKoD3zz4YNRJo9nIa5kAIkMhHtlFEcF0tbXmKmxitD+Ri+zJnS4mL18cUrnRlhjheY6c16FTzalnSKLRQDDXNApWDO/9AXlzQ5NKQQgOvzFcOK02Yy1crOIzar+lK9QVt+Zbd3F1jqflSSIuGGbmzqfPSUqi31JfVq5gj1wWZwRent+62DZI1Gk1CXfopk+z+w5eXFregR9ZAUpRiK3cFkIMLepMhK4oQKBgQD2DAjwCcd2H2QK/POSQhfc++bB5ZNKnRK53uTWSkii2WyAYTfxFBOxK8IZZ6lmE5vNO2OKJIYaH6A3jQE0rE2JiXgEauYhp3iS/J9RtjmZPEl1vlI7ELkc8t/yawvPi82xPZ1PKpsO5aUSVW6ozw5k2ShfRS75lKJ7Yt8TXP6INQKBgQD16sqm613oM0U5VEzdAtOo1EeB1ZM+fMBBTd+veqG7gPtb7AR9buTLi8p87b6npA4lgfr07ha3garEO9oZmy4MEIDBlCVb/McOqEZXII9slpcWwWwVXL+soRKPAjY4K4+r/3a044eTphaLve3HBhIhC8e7CO7XvgA4rihQTzx53QKBgCH2K02mq+d8Eb0KiTxI7y5LfuCIpboI0Erjn0aM3lXMGRPnV2dpVAaCeboz+sfiMQE1D1pEDFaSwvSn++CfX9x6IxzI/JbsnNH9GKiYtH6YObOM36DTgBmk1JCLggfVzkCGtq30vY5i2FQdgra+TchRySbNT9yXTY4maZAsp915AoGBANE2Nb/6H0MrUyopwNaJ0B4iss8PLxyLL1ifcrysXKnTWoTibxNzY2yTeen8rSWb2XkpcqIrZ+Ioi2o07SC5t1wGMjP94Ca5D3Q1ztnS1pHwL4vpdBVceajYw5wsqonw7WLLjGbp527Cbw3lwEOAs62vgvVo7SFYAII4EA36yx11AoGBAO+LUxVk9C7BShM9bcV479zCp4HTz1G3/FRk17FYOGFe3ZD+ueworMFTZidQbMevBH9g9m6jmP4WHdJ5BmvJeb/r4ZO+aJh1TvmLs5xdd4R8b34jTkrr1CDRLhiSWunwKLODsooa56i+JBBh3McKADc/o4xJ7JkT/lC5RG3jm6rv"
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZnRxeMSOINq5SUdh7jJ9D99ffppPqruejTYxI6WDXvgjykvX2erB9r2sFPyWA6VtzH5MxLb7iUQm8ixv5XhG1ImIZ8RAw2bdkaLD2Km94H7OtZcAyEGXjMEazI6/qfKJjpgA9oz9Ei2AokLnvX9B75Rnx7/cW1GF3+bJEyT9Nk7t74wDvp4QeSmejJDq8Exzex0hksUjUWI+Mj9KhqFT0/AU9icbLNv5wfkMBqZW6Z3garPv0pfVYgZm0bBgyBVB9Bi9WMZ57puPixfBXJ6cyD26izap0ly4rJni/RQHfFtOHaj+Sr+WmDNZ/X4Wd7roS+0CgXjOUBaJdX5XJ0zUQIDAQAB"
api_base_url: "https://platformtest.xqdmipay.com"
http_timeout: "10s"
environment_prod:
mer_account: "6000055d34f445418124ab7c0beb81a6"
mer_no: "10001910"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVDVrlVS+HkfLx+56v1Fyfqj5Gd+DRkPIK4EOu+SMi+wtP4dwPBeXkrL1w+nSC0UFQ2Py690qdRu1FCSTNMWC8kfzddC4xlckJKXa9NoDyeJIN/Z5Za9Fg2znfqTee9BE8NnJk4EtmRwKJQaP8sCrYsIDv/bagywM9t25lKn2bmUOZKVVUtn/Xf5OBYDE6AVHB83J+HxX5VPLie+dbRdsRR+hoZs/vzLTNlZsTcrAnWUf7cqd9XNr39gXnXgdw61kzAC9RtSLbRPAo474F03xmLZKsL70vmBgex9/paljPxNnFVq1CPxmam5yzY0NtS6iXUlU7ttqAzBolSwPWla7QIDAQAB"
private_key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9UNWuVVL4eR8vH7nq/UXJ+qPkZ34NGQ8grgQ675IyL7C0/h3A8F5eSsvXD6dILRQVDY/Lr3Sp1G7UUJJM0xYLyR/N10LjGVyQkpdr02gPJ4kg39nllr0WDbOd+pN570ETw2cmTgS2ZHAolBo/ywKtiwgO/9tqDLAz23bmUqfZuZQ5kpVVS2f9d/k4FgMToBUcHzcn4fFflU8uJ751tF2xFH6Ghmz+/MtM2VmxNysCdZR/typ31c2vf2BedeB3DrWTMAL1G1IttE8CjjvgXTfGYtkqwvvS+YGB7H3+lqWM/E2cVWrUI/GZqbnLNjQ21LqJdSVTu22oDMGiVLA9aVrtAgMBAAECggEBAI/jZ3VoTnaiAIydjX5IYAnC4VxROKIV4MSS3o441iIk0ybNWanyR5ddPA7KS/d0o6XYt+k1AvOtjUr7riaL7V6pz+1wZdsbxJnxgPsoJBgYkYYV/ZQdfLvNUC6LbBmqOgkeZEDd3YEPV5vP7R99Whyy5j4YQxkYabgQXw9x1TeKHtCVY7DROTBaKcXH+OKrF73GeJfxACIlgcG9RUdiTnmmRoSfrDN2zQy1RiWCBiQhoUYYfJrPtC1IRd8HE8M3ctLchoIQKJ9Zu+5gHM1KaARkn/Hkk8Mo1uzwnvsDgI5Mjcm403gm3/rIlH2q4+LSMtNJib3hqFrVEJ6cM8AgG8ECgYEA+wacF72UY+YjZCp7mJk4QwJEHUvws+mqY2uzONS/cDpODoCnZAMejEmVn0kCuY+kjD79YBduPuJTzrZoUS+YfqIBxHryUPbXJOs2l9la/o6P3Nbo+ILDBKNp7Fm0t96Z6Va7jwyVpclL0NXpv4Q4VP2TfDFxp/1xjSZRPSCjdP0CgYEAwREvfEVPTWROktftppH2/NS0Kv88o+YfnF/upRwIYYxl4zAPT4WUPvwELLwW9xfmt/IQGoY/6t/Vk0YZ1B14uPKNEyoJyMqDP6p6kT7vUwI8uPUP/n5wW3bLKJnoScKbgCQ+M3P/TRsOJQlthnS2EzcmqZgmCqfULaqEE89w2LECgYBe0pxcC2zmX6S2zaVqe1ZZWZ3JQ0pla7rFW4WTzimShzO9HrQcf2EmtRUj2jyBQ9VwdMrZZYBrmKr3xseZA1WjYCcyxQ6LrvKOK5uvuJc62TdWwIe4eAyaz+/PLAOsARY6olyvKJ3Oxj8xX9ywT43H7RGtNDAuuPoPy42cfZvBMQKBgFAQemrEq3Biyprm5O0Q1yZeZyD1nAY0JqPIvMTH7UnW2WHvykmmEaZVCL4sejGaPdnGjpsRVWxnysA6b/ehCTFZlNt/sXMNWISMhCu7t6/q25ewOSPG931WtEVwHf6Ir8fiP9FCp3soXyNI15zMxb0OQABQ0mXU147giclVW2zhAoGBAPlW9hqbWtHQIdXAnsCLqa4YaBNex+ghv1tjcsi79uiydg5RjEiWz43xzEQrywnALXEHqjSShvBsHVpa2uTOlpA515UqgLyl7JIeqAKrPx+5qKIo8901OG/u/b00x0GTdF3wYpTavqcaFexNTzfylYUs8FueLNVh9NvTSqjEHjvo"
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Kt1qR5jwf4xUVHqo2pLZW2Xb43P9c8BjMHeq4ih+u+8Qr5YtJa2EPv/sNoAQktjaUhsg9tJvtn1Pc46xIo3XeZiicdn91eNSdC6mZ8NxT6IJyyEr5x15o6hJORkiDbYg8k3rf40bZl8B6Oz6pEGPIYrmO8DVWN0Ak7qmWhHF5ePKusfLjy4TWEt2JmQGHAz+lfkDGaQzwtrC2kt4adYwcdpY78B4fH8Ssofr2fLuMQYl2QYWIV0lplAQicuTRhgWj4tora/MoK/LbKKFCthrElGvVJtial1QCfhOOUVgdjzGKdmuer8qiuseDraVIKYkAjuY9fGBWF+2N7mNIWOKwIDAQAB"
api_base_url: "https://platform.xqdmipay.com"
http_timeout: "10s"
tron_grid:
enabled: true
api_base_url: "https://api.trongrid.io"
api_key: ""
usdt_contract_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
usdt_contract_address: "TCSTWxGagPpCS8RaZeBXMW9d69gUsK9QGb"
http_timeout: "10s"
external_recharge:
usdt_trc20_enabled: true
usdt_trc20_address: ""

View File

@ -52,21 +52,32 @@ google_play:
http_timeout: "10s"
consume_enabled: true
mifapay:
# MiFaPay 是 H5 统一三方支付入口;商户私钥必须通过密钥系统或环境配置提供,不能把商家公钥写进 private_key
# MiFaPay 是 H5 统一三方支付入口;商家公钥只用于记录商户侧配置,真实下单签名必须继续使用商户私钥
enabled: true
mer_account: "6000055d34f445418124ab7c0beb81a6"
mer_no: "10001910"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVDVrlVS+HkfLx+56v1Fyfqj5Gd+DRkPIK4EOu+SMi+wtP4dwPBeXkrL1w+nSC0UFQ2Py690qdRu1FCSTNMWC8kfzddC4xlckJKXa9NoDyeJIN/Z5Za9Fg2znfqTee9BE8NnJk4EtmRwKJQaP8sCrYsIDv/bagywM9t25lKn2bmUOZKVVUtn/Xf5OBYDE6AVHB83J+HxX5VPLie+dbRdsRR+hoZs/vzLTNlZsTcrAnWUf7cqd9XNr39gXnXgdw61kzAC9RtSLbRPAo474F03xmLZKsL70vmBgex9/paljPxNnFVq1CPxmam5yzY0NtS6iXUlU7ttqAzBolSwPWla7QIDAQAB"
private_key: "MIFAPAY_RSA_PRIVATE_KEY_PKCS8"
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Kt1qR5jwf4xUVHqo2pLZW2Xb43P9c8BjMHeq4ih+u+8Qr5YtJa2EPv/sNoAQktjaUhsg9tJvtn1Pc46xIo3XeZiicdn91eNSdC6mZ8NxT6IJyyEr5x15o6hJORkiDbYg8k3rf40bZl8B6Oz6pEGPIYrmO8DVWN0Ak7qmWhHF5ePKusfLjy4TWEt2JmQGHAz+lfkDGaQzwtrC2kt4adYwcdpY78B4fH8Ssofr2fLuMQYl2QYWIV0lplAQicuTRhgWj4tora/MoK/LbKKFCthrElGvVJtial1QCfhOOUVgdjzGKdmuer8qiuseDraVIKYkAjuY9fGBWF+2N7mNIWOKwIDAQAB"
api_base_url: "https://platform.xqdmipay.com"
http_timeout: "10s"
environment: "prod" # 可选值test/prod切换环境时必须保证后台商户公钥和本地私钥是一对。
environment_test:
mer_account: "d00f5fc97a114a0db291eceaf9841739"
mer_no: "10001925"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7FsuU9HXVXuFMKMbz10Hq0B3JfOkPJZwUfEUTdST3UuHpkp90LVLCoYfHJ8W9tV1HUhvZ+taTWrPY82vL5KPkyKok/M64NCRR3Gf/dojm6W+/ajylBhkQYiR/aksXCVTbjgt8eAbWCHpsoqqji0ZjdVZM/br6yHz89mm3nWK3GMPheRjwC2LROUdqOkpb2H3C4PKEm/zGBW0/88uSDIUzsoKwyMOhMyJuXqI+HMpMG3SNT732f4SllJrrF/reRJnok87LqBPOTCfAVeEwgWhk0PD6sktdISarqnVgYqfGBpAS+AmqhaNforZ6UTdNFDBMithau+6f/qC3+rr3YiiwQIDAQAB"
private_key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDsWy5T0ddVe4UwoxvPXQerQHcl86Q8lnBR8RRN1JPdS4emSn3QtUsKhh8cnxb21XUdSG9n61pNas9jza8vko+TIqiT8zrg0JFHcZ/92iObpb79qPKUGGRBiJH9qSxcJVNuOC3x4BtYIemyiqqOLRmN1Vkz9uvrIfPz2abedYrcYw+F5GPALYtE5R2o6SlvYfcLg8oSb/MYFbT/zy5IMhTOygrDIw6EzIm5eoj4cykwbdI1PvfZ/hKWUmusX+t5EmeiTzsuoE85MJ8BV4TCBaGTQ8PqyS10hJquqdWBip8YGkBL4CaqFo1+itnpRN00UMEyK2Fq77p/+oLf6uvdiKLBAgMBAAECggEALvaXJ/SEEuouNtHSDsvvYCm5AwN8WMWTn9SFMknQ76G4XGRkx3meZYLs36UEzRrw4FaqPD3ZfZSBjNUrwAohGR1D3dHwmwcWNtnu7mPPu3edkY1mVeLa2OKoD3zz4YNRJo9nIa5kAIkMhHtlFEcF0tbXmKmxitD+Ri+zJnS4mL18cUrnRlhjheY6c16FTzalnSKLRQDDXNApWDO/9AXlzQ5NKQQgOvzFcOK02Yy1crOIzar+lK9QVt+Zbd3F1jqflSSIuGGbmzqfPSUqi31JfVq5gj1wWZwRent+62DZI1Gk1CXfopk+z+w5eXFregR9ZAUpRiK3cFkIMLepMhK4oQKBgQD2DAjwCcd2H2QK/POSQhfc++bB5ZNKnRK53uTWSkii2WyAYTfxFBOxK8IZZ6lmE5vNO2OKJIYaH6A3jQE0rE2JiXgEauYhp3iS/J9RtjmZPEl1vlI7ELkc8t/yawvPi82xPZ1PKpsO5aUSVW6ozw5k2ShfRS75lKJ7Yt8TXP6INQKBgQD16sqm613oM0U5VEzdAtOo1EeB1ZM+fMBBTd+veqG7gPtb7AR9buTLi8p87b6npA4lgfr07ha3garEO9oZmy4MEIDBlCVb/McOqEZXII9slpcWwWwVXL+soRKPAjY4K4+r/3a044eTphaLve3HBhIhC8e7CO7XvgA4rihQTzx53QKBgCH2K02mq+d8Eb0KiTxI7y5LfuCIpboI0Erjn0aM3lXMGRPnV2dpVAaCeboz+sfiMQE1D1pEDFaSwvSn++CfX9x6IxzI/JbsnNH9GKiYtH6YObOM36DTgBmk1JCLggfVzkCGtq30vY5i2FQdgra+TchRySbNT9yXTY4maZAsp915AoGBANE2Nb/6H0MrUyopwNaJ0B4iss8PLxyLL1ifcrysXKnTWoTibxNzY2yTeen8rSWb2XkpcqIrZ+Ioi2o07SC5t1wGMjP94Ca5D3Q1ztnS1pHwL4vpdBVceajYw5wsqonw7WLLjGbp527Cbw3lwEOAs62vgvVo7SFYAII4EA36yx11AoGBAO+LUxVk9C7BShM9bcV479zCp4HTz1G3/FRk17FYOGFe3ZD+ueworMFTZidQbMevBH9g9m6jmP4WHdJ5BmvJeb/r4ZO+aJh1TvmLs5xdd4R8b34jTkrr1CDRLhiSWunwKLODsooa56i+JBBh3McKADc/o4xJ7JkT/lC5RG3jm6rv"
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZnRxeMSOINq5SUdh7jJ9D99ffppPqruejTYxI6WDXvgjykvX2erB9r2sFPyWA6VtzH5MxLb7iUQm8ixv5XhG1ImIZ8RAw2bdkaLD2Km94H7OtZcAyEGXjMEazI6/qfKJjpgA9oz9Ei2AokLnvX9B75Rnx7/cW1GF3+bJEyT9Nk7t74wDvp4QeSmejJDq8Exzex0hksUjUWI+Mj9KhqFT0/AU9icbLNv5wfkMBqZW6Z3garPv0pfVYgZm0bBgyBVB9Bi9WMZ57puPixfBXJ6cyD26izap0ly4rJni/RQHfFtOHaj+Sr+WmDNZ/X4Wd7roS+0CgXjOUBaJdX5XJ0zUQIDAQAB"
api_base_url: "https://platformtest.xqdmipay.com"
http_timeout: "10s"
environment_prod:
mer_account: "6000055d34f445418124ab7c0beb81a6"
mer_no: "10001910"
merchant_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVDVrlVS+HkfLx+56v1Fyfqj5Gd+DRkPIK4EOu+SMi+wtP4dwPBeXkrL1w+nSC0UFQ2Py690qdRu1FCSTNMWC8kfzddC4xlckJKXa9NoDyeJIN/Z5Za9Fg2znfqTee9BE8NnJk4EtmRwKJQaP8sCrYsIDv/bagywM9t25lKn2bmUOZKVVUtn/Xf5OBYDE6AVHB83J+HxX5VPLie+dbRdsRR+hoZs/vzLTNlZsTcrAnWUf7cqd9XNr39gXnXgdw61kzAC9RtSLbRPAo474F03xmLZKsL70vmBgex9/paljPxNnFVq1CPxmam5yzY0NtS6iXUlU7ttqAzBolSwPWla7QIDAQAB"
private_key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9UNWuVVL4eR8vH7nq/UXJ+qPkZ34NGQ8grgQ675IyL7C0/h3A8F5eSsvXD6dILRQVDY/Lr3Sp1G7UUJJM0xYLyR/N10LjGVyQkpdr02gPJ4kg39nllr0WDbOd+pN570ETw2cmTgS2ZHAolBo/ywKtiwgO/9tqDLAz23bmUqfZuZQ5kpVVS2f9d/k4FgMToBUcHzcn4fFflU8uJ751tF2xFH6Ghmz+/MtM2VmxNysCdZR/typ31c2vf2BedeB3DrWTMAL1G1IttE8CjjvgXTfGYtkqwvvS+YGB7H3+lqWM/E2cVWrUI/GZqbnLNjQ21LqJdSVTu22oDMGiVLA9aVrtAgMBAAECggEBAI/jZ3VoTnaiAIydjX5IYAnC4VxROKIV4MSS3o441iIk0ybNWanyR5ddPA7KS/d0o6XYt+k1AvOtjUr7riaL7V6pz+1wZdsbxJnxgPsoJBgYkYYV/ZQdfLvNUC6LbBmqOgkeZEDd3YEPV5vP7R99Whyy5j4YQxkYabgQXw9x1TeKHtCVY7DROTBaKcXH+OKrF73GeJfxACIlgcG9RUdiTnmmRoSfrDN2zQy1RiWCBiQhoUYYfJrPtC1IRd8HE8M3ctLchoIQKJ9Zu+5gHM1KaARkn/Hkk8Mo1uzwnvsDgI5Mjcm403gm3/rIlH2q4+LSMtNJib3hqFrVEJ6cM8AgG8ECgYEA+wacF72UY+YjZCp7mJk4QwJEHUvws+mqY2uzONS/cDpODoCnZAMejEmVn0kCuY+kjD79YBduPuJTzrZoUS+YfqIBxHryUPbXJOs2l9la/o6P3Nbo+ILDBKNp7Fm0t96Z6Va7jwyVpclL0NXpv4Q4VP2TfDFxp/1xjSZRPSCjdP0CgYEAwREvfEVPTWROktftppH2/NS0Kv88o+YfnF/upRwIYYxl4zAPT4WUPvwELLwW9xfmt/IQGoY/6t/Vk0YZ1B14uPKNEyoJyMqDP6p6kT7vUwI8uPUP/n5wW3bLKJnoScKbgCQ+M3P/TRsOJQlthnS2EzcmqZgmCqfULaqEE89w2LECgYBe0pxcC2zmX6S2zaVqe1ZZWZ3JQ0pla7rFW4WTzimShzO9HrQcf2EmtRUj2jyBQ9VwdMrZZYBrmKr3xseZA1WjYCcyxQ6LrvKOK5uvuJc62TdWwIe4eAyaz+/PLAOsARY6olyvKJ3Oxj8xX9ywT43H7RGtNDAuuPoPy42cfZvBMQKBgFAQemrEq3Biyprm5O0Q1yZeZyD1nAY0JqPIvMTH7UnW2WHvykmmEaZVCL4sejGaPdnGjpsRVWxnysA6b/ehCTFZlNt/sXMNWISMhCu7t6/q25ewOSPG931WtEVwHf6Ir8fiP9FCp3soXyNI15zMxb0OQABQ0mXU147giclVW2zhAoGBAPlW9hqbWtHQIdXAnsCLqa4YaBNex+ghv1tjcsi79uiydg5RjEiWz43xzEQrywnALXEHqjSShvBsHVpa2uTOlpA515UqgLyl7JIeqAKrPx+5qKIo8901OG/u/b00x0GTdF3wYpTavqcaFexNTzfylYUs8FueLNVh9NvTSqjEHjvo"
platform_public_key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Kt1qR5jwf4xUVHqo2pLZW2Xb43P9c8BjMHeq4ih+u+8Qr5YtJa2EPv/sNoAQktjaUhsg9tJvtn1Pc46xIo3XeZiicdn91eNSdC6mZ8NxT6IJyyEr5x15o6hJORkiDbYg8k3rf40bZl8B6Oz6pEGPIYrmO8DVWN0Ak7qmWhHF5ePKusfLjy4TWEt2JmQGHAz+lfkDGaQzwtrC2kt4adYwcdpY78B4fH8Ssofr2fLuMQYl2QYWIV0lplAQicuTRhgWj4tora/MoK/LbKKFCthrElGvVJtial1QCfhOOUVgdjzGKdmuer8qiuseDraVIKYkAjuY9fGBWF+2N7mNIWOKwIDAQAB"
api_base_url: "https://platform.xqdmipay.com"
http_timeout: "10s"
tron_grid:
enabled: true
api_base_url: "https://api.trongrid.io"
api_key: "TRONGRID_API_KEY"
usdt_contract_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
usdt_contract_address: "TCSTWxGagPpCS8RaZeBXMW9d69gUsK9QGb"
http_timeout: "10s"
external_recharge:
usdt_trc20_enabled: true
usdt_trc20_address: "TRC20_PLATFORM_RECEIVE_ADDRESS"