feat: wire lucky gift go flow and reward config updates

This commit is contained in:
hy001 2026-04-18 18:53:09 +08:00
parent 7331cfea51
commit 621b15079e
28 changed files with 1067 additions and 379 deletions

View File

@ -10,12 +10,12 @@ spring:
red-circle: red-circle:
log: log:
tencent-cls: tencent-cls:
secret-id: IKID1pNfgOmrc4G8frlNfcEWU7PMkrd4AwNU secret-id: ${LIKEI_TENCENT_CLS_SECRET_ID}
secret-key: oISIp41i7F6fwvby1kCLBivsWqrZ07vV secret-key: ${LIKEI_TENCENT_CLS_SECRET_KEY}
endpoint: ap-singapore.cls.tencentcs.com endpoint: ${LIKEI_TENCENT_CLS_ENDPOINT}
region: ap-singapore region: ${LIKEI_TENCENT_CLS_REGION}
rtc: rtc:
appId: 4b5e5cea3b86476caf7f7a57d05b82d1 appId: ${LIKEI_RTC_APP_ID}
certificate: a6feb209de6448148a926f59634807bb certificate: ${LIKEI_RTC_CERTIFICATE}
killRoom: https://api.sd-rtn.com/dev/v1/kicking-rule killRoom: ${LIKEI_RTC_KILL_ROOM_URL}
authKey: Basic ZTA0MTVjMzYwZjBmNDNhZGFhNTdjZDZmNjgwYTFiZWQ6MWIyYmNjZDU0NGQzNDRhYmJhMTNiNDliZjUyMGY4MTI= authKey: ${LIKEI_RTC_AUTH_KEY}

View File

@ -1,19 +1,21 @@
framework: framework:
nacos: nacos:
subscribeServices: subscribeServices:
- rc-auth - rc-auth
- rc-service-console - rc-gateway
- rc-service-external - rc-service-console
- rc-service-order - rc-service-external
- rc-service-other - rc-service-order
- rc-service-team - rc-service-other
- rc-service-user - rc-service-wallet
- rc-service-wallet - rc-service-live
- rc-service-live - rc-scheduling
healthEndpoint: /actuator/health - game-fruit
healthStatus: UP - visual-monitor
healthCheckSleepTime: 5000 healthEndpoint: /actuator/health
healthSuccessWaitTime: 5000 healthStatus: UP
instanceDownWaitTime: 15000 healthCheckSleepTime: 5000
stopAfterWaitTime: 5000 healthSuccessWaitTime: 5000
stopKey: CxILm9hA1b9hF3Hl instanceDownWaitTime: 15000
stopAfterWaitTime: 5000
stopKey: ${LIKEI_FRAMEWORK_NACOS_STOP_KEY}

View File

@ -1,7 +1,7 @@
spring: spring:
data: data:
mongodb: mongodb:
uri: mongodb://root:123456@localhost:27017/tarab_all?authSource=admin&readPreference=secondaryPreferred&retryWrites=false&maxPoolSize=50&minPoolSize=5&maxIdleTimeMS=6000 uri: ${LIKEI_MONGO_URI}
logging: logging:

View File

@ -3,10 +3,9 @@ spring:
datasource: datasource:
type: com.zaxxer.hikari.HikariDataSource type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.p6spy.engine.spy.P6SpyDriver driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/likei?characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&autoReconnect=true url: ${LIKEI_MYSQL_JDBC_URL}
# url: jdbc:p6spy:mysql://10.0.17.81:3306/likei?characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&autoReconnect=true username: ${LIKEI_MYSQL_USERNAME}
username: root password: ${LIKEI_MYSQL_PASSWORD}
password: 123456
hikari: hikari:
# 连接池名称 # 连接池名称
@ -22,4 +21,4 @@ spring:
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认1800000即30分钟 # 此属性控制池中连接的最长生命周期值0表示无限生命周期默认1800000即30分钟
max-lifetime: 1800000 max-lifetime: 1800000
# 数据库连接超时时间,默认30秒即30000 # 数据库连接超时时间,默认30秒即30000
connection-timeout: 30000 connection-timeout: 30000

View File

@ -1,13 +1,13 @@
spring: spring:
data: data:
redis: redis:
port: 6379 port: ${LIKEI_REDIS_PORT}
host: localhost host: ${LIKEI_REDIS_HOST}
# username: prod # username: prod
ssl: ssl:
enabled: false enabled: false
database: 0 database: ${LIKEI_REDIS_DATABASE}
timeout: 120000 timeout: 120000
lettuce: lettuce:
pool: pool:
@ -16,4 +16,4 @@ spring:
min-idle: 2 min-idle: 2
max-active: 8 max-active: 8
max-wait: 120000ms max-wait: 120000ms
time-between-eviction-runs: 60000ms time-between-eviction-runs: 60000ms

View File

@ -1,4 +1,5 @@
rocketmq: rocketmq:
accessKey: ak9ogoaw3zm5b5d2b2e4f05 accessKey: ${LIKEI_ROCKETMQ_ACCESS_KEY}
secretKey: sk0caf0e8a8b5a9109 secretKey: ${LIKEI_ROCKETMQ_SECRET_KEY}
endpoints: rmq-9ogoaw3zm.rocketmq.sg.qcloud.tencenttdmq.com:8080 endpoints: ${LIKEI_ROCKETMQ_ENDPOINT}
local-disable: ${LIKEI_ROCKETMQ_LOCAL_DISABLE}

View File

@ -11,81 +11,93 @@ spring:
maxAge: 360000 maxAge: 360000
routes: routes:
- id: service-auth - id: service-auth
uri: lb://rc-auth uri: ${LIKEI_GATEWAY_ROUTE_AUTH_URI}
predicates: predicates:
- Path=/auth/** - Path=/auth/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: service-external - id: service-external
uri: lb://rc-service-external uri: ${LIKEI_GATEWAY_ROUTE_EXTERNAL_URI}
predicates: predicates:
- Path=/external/** - Path=/external/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: service-order - id: service-order
uri: lb://rc-service-order uri: ${LIKEI_GATEWAY_ROUTE_ORDER_URI}
predicates: predicates:
- Path=/order/** - Path=/order/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: service-wallet - id: service-wallet
uri: lb://rc-service-wallet uri: ${LIKEI_GATEWAY_ROUTE_WALLET_URI}
predicates: predicates:
- Path=/wallet/** - Path=/wallet/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: service-live - id: service-live
uri: lb://rc-service-live uri: ${LIKEI_GATEWAY_ROUTE_LIVE_URI}
predicates: predicates:
- Path=/live/** - Path=/live/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
- id: invite-campaign-public - id: invite-campaign-public
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_INVITE_PUBLIC_URI}
predicates: predicates:
- Path=/public/h5/invite-campaign/** - Path=/public/h5/invite-campaign/**
- id: invite-campaign-app - id: invite-campaign-app
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_INVITE_APP_URI}
predicates: predicates:
- Path=/app/h5/invite-campaign/** - Path=/app/h5/invite-campaign/**
- id: register-reward-app
uri: ${LIKEI_GATEWAY_ROUTE_REGISTER_REWARD_APP_URI}
predicates:
- Path=/app/register-reward/**
- id: go-service
uri: ${LIKEI_GATEWAY_ROUTE_GO_URI}
predicates:
- Path=/go/**
filters:
- StripPrefix=1
- id: invite-campaign-internal - id: invite-campaign-internal
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_INVITE_INTERNAL_URI}
predicates: predicates:
- Path=/internal/invite-campaign/** - Path=/internal/invite-campaign/**
- id: game-app - id: game-app
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_GAME_APP_URI}
predicates: predicates:
- Path=/app/game/** - Path=/app/game/**
- id: game-internal - id: game-internal
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_GAME_INTERNAL_URI}
predicates: predicates:
- Path=/internal/game/baishun/** - Path=/internal/game/baishun/**
- id: game-baishun-callback - id: game-baishun-callback
uri: http://10.2.1.16:2900 uri: ${LIKEI_GATEWAY_ROUTE_GAME_BAISHUN_URI}
predicates: predicates:
- Path=/game/baishun/** - Path=/game/baishun/**
- id: service-gateway - id: service-gateway
uri: lb://rc-service-gateway uri: ${LIKEI_GATEWAY_ROUTE_FORWARD_URI}
predicates: predicates:
- Header=Req-Likei, true - Header=Req-Likei, true
filters: filters:
- name: ForwardRoute - name: ForwardRoute
args: args:
aesKey: 7NcAa111UGiRlRiR aesKey: ${LIKEI_GATEWAY_FORWARD_ROUTE_AES_KEY}
- id: service-other - id: service-other
uri: lb://rc-service-other uri: ${LIKEI_GATEWAY_ROUTE_OTHER_URI}
predicates: predicates:
- Path=/** - Path=/**
gateway: gateway:
@ -139,6 +151,11 @@ gateway:
- /activity/king-queen/** - /activity/king-queen/**
# week-star # week-star
- /activity/week-star/** - /activity/week-star/**
- /go/public/**
- /public/h5/week-star/**
- /go/resident-activity/register-reward/**
- /go/resident-activity/specified-gift-weekly-rank/**
- /go/resident-activity/week-star/**
# leaderboard # leaderboard
- /activity/leaderboard/gifts-send - /activity/leaderboard/gifts-send
- /activity/leaderboard/gifts-received - /activity/leaderboard/gifts-received
@ -147,4 +164,4 @@ gateway:
- /sys/version/manage/latest/review - /sys/version/manage/latest/review
- /game/yomi/** - /game/yomi/**
- /public/h5/invite-campaign/** - /public/h5/invite-campaign/**
forward-aes-key: 8NcSaTt8EHjRlRuG forward-aes-key: ${LIKEI_GATEWAY_FORWARD_AES_KEY}

View File

@ -1,72 +1,72 @@
red-circle: red-circle:
ai: ai:
minimax: minimax:
url: https://api.minimax.io/v1/text/chatcompletion_v2 url: ${LIKEI_AI_MINIMAX_URL}
authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiJ0b255IGxpdSIsIlVzZXJOYW1lIjoidG9ueSBsaXUiLCJBY2NvdW50IjoiIiwiU3ViamVjdElEIjoiMTkzMDg0MzI0Nzg4NjczMzY4NCIsIlBob25lIjoiIiwiR3JvdXBJRCI6IjE5MzA4NDMyNDc4ODI1MzkzODAiLCJQYWdlTmFtZSI6IiIsIk1haWwiOiJsaXV0YW90b255M0BpY2xvdWQuY29tIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDYtMjUgMTQ6MzA6MjYiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.TAHcSE-3YSSLWC9z9424GVF6twqi3Po5LkpGENtLF25397IvEV-CiXDFzBE5F-H6w9yG-YAROwGy0jFxwoDWPF4IsC2emKp5Qan5geavx7YqTEUQ4vJzhu7TJgDrvvUcUanVPQRBo5IyqpPuDagNPHhmPca7wgOrVHQfahUs7Q5VwOUiUDguHdwXcl6h4Yk32Ufv7rHDuS_sZnuAXxG_dY_XfIkJGwdMz7O7c9uWICnnMFXAL7GEyhy50MKJoEiCFLWnIC6Tu20oTnd2QBDlp1JCzdphA9FpBqo0SVCSmR2CZK1Uo4oXioxizkfv4EgPpCZUkOVSqT2f74l1zbFe-g authorization: ${LIKEI_AI_MINIMAX_AUTHORIZATION}
model: MiniMax-Text-01 model: ${LIKEI_AI_MINIMAX_MODEL}
qian-fan: qian-fan:
url: https://qianfan.baidubce.com/v2/chat/completions url: ${LIKEI_AI_QIANFAN_URL}
appId: '' appId: ${LIKEI_AI_QIANFAN_APP_ID:}
authorization: Bearer bce-v3/ALTAK-DjBrg6HP36lGomporE2iT/3a509ddcafca5e22cea75c85f5bd9b9e11f8d192 authorization: ${LIKEI_AI_QIANFAN_AUTHORIZATION}
model: c0jkrl3v_dt24b model: ${LIKEI_AI_QIANFAN_MODEL}
tts: tts:
url: http://128.168.134.215:9001/tts/stream url: ${LIKEI_AI_TTS_URL}
model: cloudsway_tts model: ${LIKEI_AI_TTS_MODEL}
oss: oss:
aliYun: aliYun:
endpoint: http://oss-accelerate.aliyuncs.com endpoint: ${LIKEI_ALIYUN_OSS_ENDPOINT}
bucketName: tkm-likei bucketName: ${LIKEI_ALIYUN_OSS_BUCKET_NAME}
accessUrl: https://media.haiyihy.com accessUrl: ${LIKEI_ALIYUN_OSS_ACCESS_URL}
access-key-id: LTAI5 access-key-id: ${LIKEI_ALIYUN_OSS_ACCESS_KEY_ID}
access-key-secret: v2Z31d access-key-secret: ${LIKEI_ALIYUN_OSS_ACCESS_KEY_SECRET}
sts: sts:
endpoint: sts.us-west-1.aliyuncs.com endpoint: ${LIKEI_ALIYUN_STS_ENDPOINT}
role-arn: acs:ram::124470563:role/stsoss role-arn: ${LIKEI_ALIYUN_STS_ROLE_ARN}
# 有效时间是900 ~ 3600 # 有效时间是900 ~ 3600
token-expire-time: 3600 token-expire-time: 3600
# policy-file: policy/bucket_write_policy.txt # policy-file: policy/bucket_write_policy.txt
tencent-cos: tencent-cos:
enabled: true enabled: ${LIKEI_TENCENT_COS_ENABLED}
secret-id: IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu secret-id: ${LIKEI_TENCENT_COS_SECRET_ID}
secret-key: nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl secret-key: ${LIKEI_TENCENT_COS_SECRET_KEY}
bucket-name: yumi-assets-1420526837 bucket-name: ${LIKEI_TENCENT_COS_BUCKET}
region: me-saudi-arabia region: ${LIKEI_TENCENT_COS_REGION}
access-url: https://media.haiyihy.com access-url: ${LIKEI_TENCENT_COS_ACCESS_URL}
instant-message: instant-message:
broadcast-group: broadcast-group:
LOTFUN: "@TGS#a3C" LOTFUN: ${LIKEI_IM_BROADCAST_GROUP_LOTFUN}
LIKEI: "@TGS#2RUK4PK5C2" LIKEI: ${LIKEI_IM_BROADCAST_GROUP_LIKEI}
tencet-trtc: tencet-trtc:
secretId: IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu secretId: ${LIKEI_TRTC_SECRET_ID}
secretKey: nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl secretKey: ${LIKEI_TRTC_SECRET_KEY}
endpoint: trtc.tencentcloudapi.com endpoint: ${LIKEI_TRTC_ENDPOINT}
sdkAppId: 20036101 sdkAppId: ${LIKEI_TRTC_SDK_APP_ID}
tencet-im: tencet-im:
appId: 20036101 appId: ${LIKEI_IM_APP_ID}
key: dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c key: ${LIKEI_IM_KEY}
identifier: yumiadmin identifier: ${LIKEI_IM_IDENTIFIER}
baseEndpoint: https://adminapisgp.im.qcloud.com baseEndpoint: ${LIKEI_IM_BASE_ENDPOINT}
noticeAccount: yuminotice noticeAccount: ${LIKEI_IM_NOTICE_ACCOUNT}
newsletterAccount: yuminotice newsletterAccount: ${LIKEI_IM_NEWSLETTER_ACCOUNT}
agora: agora:
appId: 4b5e5cea3b86476caf7f7a57d05b82d1 appId: ${LIKEI_AGORA_APP_ID}
appCertificate: a6feb209de6448148a926f59634807bb appCertificate: ${LIKEI_AGORA_APP_CERTIFICATE}
tokenExpireSecond: 86400 tokenExpireSecond: ${LIKEI_AGORA_TOKEN_EXPIRE_SECOND}
privilegeExpireSecond: 86400 privilegeExpireSecond: ${LIKEI_AGORA_PRIVILEGE_EXPIRE_SECOND}
authKey: Basic ZTA0MTVjMzYwZjBmNDNhZGFhNTdjZDZmNjgwYTFiZWQ6MWIyYmNjZDU0NGQzNDRhYmJhMTNiNDliZjUyMGY4MTI= authKey: ${LIKEI_AGORA_AUTH_KEY}
sms: sms:
aliYun: aliYun:
enabled: true enabled: ${LIKEI_SMS_ALIYUN_ENABLED}
sign-name: Tarab sign-name: ${LIKEI_SMS_ALIYUN_SIGN_NAME}
access-key-id: LTAI4xxxxxxU8JQ6Xf access-key-id: ${LIKEI_SMS_ALIYUN_ACCESS_KEY_ID}
access-key-secret: hh2DrAxxxxxxW5bQTA7s1 access-key-secret: ${LIKEI_SMS_ALIYUN_ACCESS_KEY_SECRET}
endpoint: dysmsapi.aliyuncs.com endpoint: ${LIKEI_SMS_ALIYUN_ENDPOINT}
censor: censor:
active: qcloud active: ${LIKEI_CENSOR_ACTIVE}
tupu: tupu:
enabled: false enabled: ${LIKEI_CENSOR_TUPU_ENABLED}
tencent-cloud: tencent-cloud:
secret-id: AKIDGMNDrNk secret-id: ${LIKEI_TENCENT_CLOUD_IMS_SECRET_ID}
secret-key: 71h9dv41lU secret-key: ${LIKEI_TENCENT_CLOUD_IMS_SECRET_KEY}
endpoint: ims.tencentcloudapi.com endpoint: ${LIKEI_TENCENT_CLOUD_IMS_ENDPOINT}
region: ap-guangzhou region: ${LIKEI_TENCENT_CLOUD_IMS_REGION}

View File

@ -1,28 +1,28 @@
red-circle: red-circle:
pay: pay:
web-pay-base-url: 'https://h5.likeichat.com/#/' web-pay-base-url: ${LIKEI_PAY_WEB_PAY_BASE_URL}
web-pay-result-page: pay-result web-pay-result-page: ${LIKEI_PAY_WEB_PAY_RESULT_PAGE}
web-pay-recharge-page: recharge web-pay-recharge-page: ${LIKEI_PAY_WEB_PAY_RECHARGE_PAGE}
web-pay-collection-page: collection-receipt web-pay-collection-page: ${LIKEI_PAY_WEB_PAY_COLLECTION_PAGE}
googlePayGlobal: googlePayGlobal:
serverAccount: server-api@api-5499404589076025365-781142.iam.gserviceaccount.com serverAccount: ${LIKEI_GOOGLE_PAY_GLOBAL_SERVER_ACCOUNT}
classPatchServiceAccountJson: payfile/google_pay.json classPatchServiceAccountJson: ${LIKEI_GOOGLE_PAY_GLOBAL_PATCH_JSON}
googlePay: googlePay:
TAXAB: TAXAB:
serverAccount: tarab-server@tarab-427706.iam.gserviceaccount.com serverAccount: ${LIKEI_GOOGLE_PAY_TAXAB_SERVER_ACCOUNT}
publicKey: MIIBIjANxxxxxxxxTjmAO68rmnKr2gYJ3isuepCZsaX0wIDAQAB publicKey: ${LIKEI_GOOGLE_PAY_TAXAB_PUBLIC_KEY}
classPatchServiceAccountJson: payfile/tarab-427706-04fe535b024a.json classPatchServiceAccountJson: ${LIKEI_GOOGLE_PAY_TAXAB_PATCH_JSON}
paypal: paypal:
merchantId: 'AZm9zUAxxxxx8kiGKL6D4l0elx2' merchantId: ${LIKEI_PAYPAL_MERCHANT_ID}
secretKey: 'EJuYA6cSud6xxxxx4_Fj9rbBh1yYnr97btui2ocuR' secretKey: ${LIKEI_PAYPAL_SECRET_KEY}
devMerchantId: 'Ac2aB2KFgz3xxxxxGmbS7dcPedRf2_eg23D' devMerchantId: ${LIKEI_PAYPAL_DEV_MERCHANT_ID}
devSecretKey: 'ECjyOP4nxxxxxxB0JEAH9P7im' devSecretKey: ${LIKEI_PAYPAL_DEV_SECRET_KEY}
huawei: huawei:
access-token: access-token:
grant-type: 'client_credentials' grant-type: ${LIKEI_HUAWEI_GRANT_TYPE}
client-secret: 'dff36e68xxxx30da9c7240ae0bc96' client-secret: ${LIKEI_HUAWEI_CLIENT_SECRET}
client-id: '11xx93' client-id: ${LIKEI_HUAWEI_CLIENT_ID}
oauth-login-url: https://oauth-login.cloud.huawei.com/oauth2/v3/token oauth-login-url: ${LIKEI_HUAWEI_OAUTH_LOGIN_URL}
host: host:
CHINA: https://orders-drcn.iap.hicloud.com CHINA: https://orders-drcn.iap.hicloud.com
GERMANY: https://orders-dre.iap.hicloud.com GERMANY: https://orders-dre.iap.hicloud.com
@ -33,45 +33,45 @@ red-circle:
PURCHASES_TOKENS_VERIFY: /applications/purchases/tokens/verify PURCHASES_TOKENS_VERIFY: /applications/purchases/tokens/verify
PURCHASES_CONFIRM: /applications/v2/purchases/confirm PURCHASES_CONFIRM: /applications/v2/purchases/confirm
PURCHASES_CANCELLED_LIST: /applications/v2/purchases/cancelledList PURCHASES_CANCELLED_LIST: /applications/v2/purchases/cancelledList
iap-public-key: MIIBojANBgkqhkiG9w0Bxxxxx7cdmApDJfpAlKeLZ9fy7d3VIWyqZiLYtxxxxj3t+sFuC4lEJBVrw5MgDE7bmpjidOm0rxxxxUYC1hSI8xXagbJ0sOcYXSunxxxx1NaupT2+ILoZPfIQVF4RThlQmphuOif4uMMlYvYosiueCKlv6MYQi0fVcLKEjWVc/XslowtLS4w0EV/eAVpFq7kTvy04LNYVscSjZop7AHEMVVoNgzg+mLC0UGsftYRfEBeKHkNppTg931qodgJSkIM582ZTK0eujAJR43On3z1gc8+UvSKW+9w+tAqw099VYrFY3sXySUfVJ6SoejiHeKlAgMBAAE= iap-public-key: ${LIKEI_HUAWEI_IAP_PUBLIC_KEY}
# uat环境 # uat环境
payer-max: payer-max:
secret-key: 8aexx98f secret-key: ${LIKEI_PAYERMAX_SECRET_KEY}
merchant-id: SDP01010 merchant-id: ${LIKEI_PAYERMAX_MERCHANT_ID}
rsa-private-key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCQU2JiAdSO8M3CQft5nZEGLO9/TPFArQCffVzWoaz3niIacJ/B3dOePJyXMljuKByoRC+1ApW+9ucVXoulkLkqUAve0q7xKMFaxCw4OAEkRC6JhjYgEJyJXLEA9KRT6EklvvomqfUwuddCKtTNLL2hFtG5+2P+BioYrekaIiZh9lIel1msn4WKoBp3LgyStcZBQOPzhD7NcKsbo+ppjT4JBSQyVZrcJ3mYe+YSV/Qnw/KY2v3OzPeLApeZhLh5wVsfcmyz04IHFogLIjRVFGU6Xbvfz8ujRtpoBD+3RSz5GKiBLPjoSgGLSIxCWc10VphKwOlvR0bi3ssKYG9HsHw5AgMBAAECggEADzebgfXrcX7WUwsd9r60UdBfGC8GqOkUzbwsE71MPXeA5QTG82vuKhr977sxQTsdemhmF1HEdDQYPVqQos5Vl66E8eOI6oh/ipBwkSTmiepedcWe41adCqapSw6AXRB61e4C9hypa4/MsH9PnKqA/AEp79AfxOLlgWCk2UqMfXuPuYhKD9SSlYVoJ5x/W48B+NBaRuSiCV3agPfnpRtMuTZ9Vs4IOL4riIyE9ABBgFinL0h/D5qSX6JnrO+N1miORSiM+2e/Sh/xs6nrCIuh9pSBcXjAeO/l4/BKCfj3TPH9hcYWWWRVgbX0WV6MDZFz/au5o9LZ7m9kUltP4dH7AQKBgQDvyrKh7BKIrwEwvt0eWBfCNdwLctb0GbsEoYVsQaiS/cLfje5289DLTTYc18fy/G8dRMGftME6qAiidtQaEb/mfSWPhHYfTayWJ0At8TvX2qbUS2b46or3lRgUBWOgpNkmLSEy7ae0I1UTStI3UN9rJNvjZ7Jntc7KGeZMfivCqQKBgQCaFMN2xBV00KerElFp0XZRaCZEyLz3MkTOwSlcs4c9cA7TTV0sZlxNRsA11WCaFIEV8TGCjZMJfmZihmB+LRXOhb45lXD+xi/JTOPs9UVOPJNpeFHuABL93/TqL0ma7d/VntKkIv2g+/CUoSzXQ6QrLg4/BpmfevZDtW/A8Gx3EQKBgQCe/TmVjM35HHfglxxLK0ONfGKKoLkPHiRW/LVXQu1/kItt6FBNRHmS4n3Xf+bOIDuYH2d1+cYImzMmbT1Sj6Q6MY3+62fad4jQAfRWwdTY2Nu2dMwwjGpZn9xYIf6dm89ytYeGmfaQxMB6yyg4jwGjq8uzqqSqiOw0Khn9a8aeCQKBgArX0zmUav4hgOslCt2rg+wOrELC7alnvDfgmAySBb5pGGH+W8Q4H97AT955+aZeMwdcReOuGt7cKlBcrIW0nog+GTjsL1t+jvZXluKiEBKFaMpPUVSyZKPBEvc4BLIGc24REznBzJ97m16aSRGNDQyM3SvKRx1WBeaV6htlz/xBAoGAbi5IvOQMCbUvtrD/lJ3xkVaoEQL6dlCVBK7Ldf5+6g/Rc9j6d5B2UVb3v9+BOpAHHFa2fIPNI8y22TmCjgIGi6O8Rm60KqFDQIQnzcmPQg9HsTIG5u0V2b/0saUj2txHRzIC+cZ4b+/xms7OHu1OKZeVIZhNdT/+CWmO2wVgA/s= rsa-private-key: ${LIKEI_PAYERMAX_RSA_PRIVATE_KEY}
rsa-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkFNiYgHUjvDNwkH7eZ2RBizvf0zxQK0An31c1qGs954iGnCfwd3TnjyclzJY7igcqEQvtQKVvvbnFV6LpZC5KlAL3tKu8SjBWsQsODgBJEQuiYY2IBCciVyxAPSkU+hJJb76Jqn1MLnXQirUzSy9oRbRuftj/gYqGK3pGiImYfZSHpdZrJ+FiqAady4MkrXGQUDj84Q+zXCrG6PqaY0+CQUkMlWa3Cd5mHvmElf0J8PymNr9zsz3iwKXmYS4ecFbH3Jss9OCBxaICyI0VRRlOl2738/Lo0baaAQ/t0Us+RiogSz46EoBi0iMQlnNdFaYSsDpb0dG4t7LCmBvR7B8OQIDAQAB rsa-public-key: ${LIKEI_PAYERMAX_RSA_PUBLIC_KEY}
platform-rsa-public-key: MIIBIjANBgkqhkiG9w0BAQEFAACBAQ8AMIIBCgKCAQEAi4+8n/BEFhWKzWs1SMdD+1gzK3xiI/wGGTS330yKSxQMM5Ec39AFQjKFTvcjIZegt2vTQYnA/AL0l0O5C98BWSBuM20/pUXd1+i/Ew/lvLYoeKDD4ARkCzJfXQcDgvm4gTZvnVJwerCN+E2rziNZoLTdTo468IArzBVFzWGa/YmQvi7brCbTlzp5EpVeZMNLNpM04I0uJIiqGpEp0PDPbbn/ZVzZLoLKO+LXWxXx1nFPVlL+X1yk1TyJVfPv7Au3mv9UXNGSF6EP21n97aaU1j29+PXNy3Yze8pmkdWmcOqGnORSLPk0Acl6gklBGyvFiSk/QsL1ocecqD8cJk1JbQIDAQAB platform-rsa-public-key: ${LIKEI_PAYERMAX_PLATFORM_RSA_PUBLIC_KEY}
app-id: d6afddeb3ca447448 app-id: ${LIKEI_PAYERMAX_APP_ID}
gateway-base-url: https://pay-gate-uat.payermax.com gateway-base-url: ${LIKEI_PAYERMAX_GATEWAY_BASE_URL}
enable-real-time-exchange-rate: false enable-real-time-exchange-rate: ${LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE}
mifa-pay: mifa-pay:
mer-account: 4dab789b6c8 mer-account: ${LIKEI_MIFA_PAY_MER_ACCOUNT}
mer-no: 1000 mer-no: ${LIKEI_MIFA_PAY_MER_NO}
gateway-base-url: https://platformtest.xqdmipay.com gateway-base-url: ${LIKEI_MIFA_PAY_GATEWAY_BASE_URL}
rsa-private-key: MIIEvgIBADANBgkqhkiG9w0BAQGFCASCBKgwggSkAgEAAoIBAQC2DZell5v2A/bfR1lTuvHsPFnzQDl8apqM72WKlRf8/AFCTLsDK2si2iKFHcf/JTL+BqKAReVwYbG0GxapleaouO95YPqH7br6J+mdpTxFVzI9AObuVybdEmrO1vE4+OqLX1EXzh88oeqkuU/lJNow12HIZABDXkj1SilAwEbgusFpZn8cZ6eTRqYYcr5bfq2uIyq1s5Hj2I6q2NwogyV12a8pkPX5y/667Kmgsg8bb+cdpFGLpLltEbm0rk7z0Dv5SWuZxKOowPfxz+ISl53RjxY+yCXks5D1Kw1EwEB0c7N8ADkbO+1BDQM1MM8IGKdTQgGUwEbT/AdhVPK39kvLAgMBAAECggEAOqQKMuaw7/+655Td6yCOiJ+wAbCwU6kq+zapqIf54B10clyw6IZ1zhYhhGthXogm8rhEY7kf/KEbUn5fQGTulW5shNZ+HIaw8Z8lmwf8cAF0Rz4hJKih9hfWm6WUsdtMAXTEdDyKx0cIg+LFH3RNa+oUry22//xA1/H5c8f7jKtQRu5rIePaRsAvMYpfTzmKXjVq0WkD9jMFgYowHWuwBc+HTvN5SI/3Ag+pXhI5dot3BMLXrLqrM7fPIH1cqi1u1jyYZIpIAEM1ZqRWJCfNmXn0YYGjswqpluqNbSgTmwMGuqhMPe1hOYJwwtXwXXSFkyO/lX8iziUbvsq5b4J6wQKBgQDamnLZc7ymnOjzg3yrm9n7SqgBsgk7pYHwl/HVdaopKm6YcsW9uTr80zYXGbTSSE65/pFCN45mkHpyyFdCoCb+FMpMyn1I6bDbDTwQPEdCo9i9uVOZM692/I/8kb9czvCqiG22Uosx3AzY/lem+XjoudDIUBha8P7cwxL64Ie/UQKBgQDVMnUERQVfLnWvdNq0W3bi2de/ynPSXDtDPHP+ezYmyyUUEIYX33BLTBFWYX9jxGVumqyOvUvmweAHTTRHPsDHrtqS/xMztxfOMNW7eBaP5Btp3pBaq/FMCUpqtYH1lMsSfLEC6iQePiAtQThvfgLuNsLm73F3vlFtBs+C3LIqWwKBgQDSn+ey3xHQkvTc1D7F9kdkGT2hTJIa11BIqY4INvP57/lZh5RBRfyw5yyBu3H+/k5kZQQ+gdsBtYlVmPSCrF6FhzCYJq3qF8ggdzL9Dac3bTkDLFKBFUyl35k4KJHx8S3vkb3r4sJdCwGR/hYkOtClo4unxYyB6xwVRxu9f6Mr0QKBgQDLa+2DOWg6vVXFKDZVyL/TDBB0C3Qfz6ksKk5zDpVIxqSGVI3d0XCQJ/CS/0xRoV82/ZaQS8ZUU8CyttOe9x1yakBb6c4klhq8vpPw4FCG0xvlFFugaFdAOc0rrCxoaqSo6xjqswXrZVPGWmjC2PVq3g1x1B3sJ0gCQ3FUZ8gH6QKBgDu+g2Adn3sF7NZKWW/sHcWhhtfx05PuFLdmA7J9LJ6TTQFW1snMp2GjkAvDx6KfwmqTT8TYZmnA0nPgz9bSgdpvCaBAdhbU6EjEcBpc3+gFwDnF4Qen8qAbXVnOE7pOrQ/F6kKaL+Xuu3dTKzJR2v6kFJRTywt+kuo3INAbN86c rsa-private-key: ${LIKEI_MIFA_PAY_RSA_PRIVATE_KEY}
platform-rsa-public-key: MIIBIjANBgkqhkiG9w1BAQEFAAOCAQ8AMIIBCgKCAQEAtjRr7TpawlzKYDFwzpUwCK+twx/0KS3W0ZVCPdOAoaVxhEDfacHkgHMUJ7MXd6raqce++k2XHFoYyD4d8fJPkjNrzQ7PPoFm774XfGxz85oemfK88AI6+3PlxEwdf0VBZXmrraJvOdD3dPv4Uq/J15PzKGSh8edYTZgeNSCD/gMRcZoZhacd0WIiaJFf/P4AEa7g+JnefatinayQXAl1n7O5kAiU7jryCzBbno7R5X96riGxUpu/Rxome/tBSBf0644jzQFU7eLA4mJ6aFchArFZ1SvMBVjpYWEgLFgQxyUbJewXRYCPU5uDvzYhFUzF/4bIdhR5swPvAPokavijKwIDAQAB platform-rsa-public-key: ${LIKEI_MIFA_PAY_PLATFORM_RSA_PUBLIC_KEY}
airwallex: airwallex:
client-id: j5v_C5xxg client-id: ${LIKEI_AIRWALLEX_CLIENT_ID}
api-key: e397fa14297xxxxxxxx6d3dff3e92c63c338 api-key: ${LIKEI_AIRWALLEX_API_KEY}
base-url: https://api-demo.airwallex.com base-url: ${LIKEI_AIRWALLEX_BASE_URL}
api-url: api-url:
AUTHENTICATION_LOGIN: /api/v1/authentication/login AUTHENTICATION_LOGIN: /api/v1/authentication/login
PAYMENT_INTENTS_CREATE: /api/v1/pa/payment_intents/create PAYMENT_INTENTS_CREATE: /api/v1/pa/payment_intents/create
paynicorn: paynicorn:
app-key: 79xx58 app-key: ${LIKEI_PAYNICORN_APP_KEY}
merchant-secret: 704a8xxx50b merchant-secret: ${LIKEI_PAYNICORN_MERCHANT_SECRET}
clipspay: clipspay:
merchantNo: 800xx2370 merchantNo: ${LIKEI_CLIPSPAY_MERCHANT_NO}
md5SecretKey: 18455c7xxxxx4a48fb7fe md5SecretKey: ${LIKEI_CLIPSPAY_MD5_SECRET_KEY}
terminalNo: 10xxx6 terminalNo: ${LIKEI_CLIPSPAY_TERMINAL_NO}
terminalKey: NzMyNGRxxxxxYThiMmE4ODA terminalKey: ${LIKEI_CLIPSPAY_TERMINAL_KEY}
notifyUrl: https://dexxxxx.com/play/server/notice/clipspay notifyUrl: ${LIKEI_CLIPSPAY_NOTIFY_URL}
placeAnOrderApi: http://uat.card.api.clipspay.com/payment/gateway/api/backTransReq placeAnOrderApi: ${LIKEI_CLIPSPAY_PLACE_ORDER_API}
redirectResult: https://dev.xxxxine.com/clipspay/redirect redirectResult: ${LIKEI_CLIPSPAY_REDIRECT_RESULT}
telegram: telegram:
bot-token: 72649:AAE7gZj0 bot-token: ${LIKEI_ORDER_TELEGRAM_BOT_TOKEN}
webhook-url: https://local.api.yuyinfang168.com/order/telegram/webhook webhook-url: ${LIKEI_ORDER_TELEGRAM_WEBHOOK_URL}

View File

@ -24,22 +24,22 @@ red-circle:
templateId: 1994334094730010626 templateId: 1994334094730010626
game: game:
hkys: hkys:
signKey: svO signKey: ${LIKEI_GAME_HKYS_SIGN_KEY}
hotgame: hotgame:
signKey: qFO signKey: ${LIKEI_GAME_HOTGAME_SIGN_KEY}
baishun: baishun:
app-id: 1704692112 app-id: ${LIKEI_GAME_BAISHUN_APP_ID}
app-key: 6EllbAruJDfw app-key: ${LIKEI_GAME_BAISHUN_APP_KEY}
app-channel: lotfun app-channel: ${LIKEI_GAME_BAISHUN_APP_CHANNEL}
baishun2fun: baishun2fun:
app-id: 26xxxx65 app-id: ${LIKEI_GAME_BAISHUN2FUN_APP_ID}
app-key: OWq58W1XDxxxxxxxzAfHqNr0l app-key: ${LIKEI_GAME_BAISHUN2FUN_APP_KEY}
app-channel: 2xxxxxn app-channel: ${LIKEI_GAME_BAISHUN2FUN_APP_CHANNEL}
sud: sud:
app-id: 178xxxx00130 app-id: ${LIKEI_GAME_SUD_APP_ID}
app-key: kAdoDDw6xxxxOphybk3G4 app-key: ${LIKEI_GAME_SUD_APP_KEY}
app-secret: Psw9s7nOnxxxxxxxS97y4uf0vW app-secret: ${LIKEI_GAME_SUD_APP_SECRET}
app-channel: axxxxt,TxxxxN app-channel: ${LIKEI_GAME_SUD_APP_CHANNEL}
static-resources: static-resources:
levelStyle: levelStyle:
wealth: wealth:
@ -82,25 +82,30 @@ red-circle:
# 测试 # 测试
lucky: lucky:
gift: gift:
go:
enabled: ${LUCKY_GIFT_GO_ENABLED}
base-url: ${GAME_LUCKY_GIFT_GO_URL}
internal-token: ${GAME_INTERNAL_CALLBACK_SECRET}
timeout-millis: ${LUCKY_GIFT_GO_TIMEOUT_MILLIS}
api: api:
enabled: true enabled: ${LUCKY_GIFT_API_ENABLED}
# 多账号配置 # 多账号配置
configs: configs:
- standardId: 18816 - standardId: ${LUCKY_GIFT_API_CONFIG_1_STANDARD_ID}
url: https://game-cn-test.jieyou.shop/lucky_gift/start_game url: ${LUCKY_GIFT_API_CONFIG_1_URL}
app_key: w0GoEN4hg app_key: ${LIKEI_GAME_BAISHUN_APP_KEY}
app_id: 929 app_id: ${LIKEI_GAME_BAISHUN_APP_ID}
app_channel: likei app_channel: ${LIKEI_GAME_BAISHUN_APP_CHANNEL}
- standardId: 19102 - standardId: ${LUCKY_GIFT_API_CONFIG_2_STANDARD_ID}
url: https://game-cn-test.jieyou.shop/lucky_gift/start_game url: ${LUCKY_GIFT_API_CONFIG_2_URL}
app_key: bXdpzw94i app_key: ${LIKEI_GAME_BAISHUN_APP_KEY}
app_id: 261 app_id: ${LIKEI_GAME_BAISHUN_APP_ID}
app_channel: likei app_channel: ${LIKEI_GAME_BAISHUN_APP_CHANNEL}
# 默认配置(向后兼容) # 默认配置(向后兼容)
url: https://game-cn-test.jieyou.shop/lucky_gift/start_game url: ${LUCKY_GIFT_API_DEFAULT_URL}
app_key: w0GoEN4hg6G app_key: ${LIKEI_GAME_BAISHUN_APP_KEY}
app_id: 9291 app_id: ${LIKEI_GAME_BAISHUN_APP_ID}
app_channel: likei app_channel: ${LIKEI_GAME_BAISHUN_APP_CHANNEL}
activity: activity:
ranking: ranking:
@ -120,13 +125,13 @@ scheduler:
telegram: telegram:
bot: bot:
token: 8350:AAGwh1O token: ${LIKEI_TELEGRAM_BOT_TOKEN}
monitor: monitor:
chat-ids: chat-ids:
- '-5081' - '${LIKEI_TELEGRAM_MONITOR_CHAT_ID_1}'
alert-limit-seconds: 60 alert-limit-seconds: ${LIKEI_TELEGRAM_MONITOR_ALERT_LIMIT_SECONDS}
proxy-host: 127.0.0.1 proxy-host: ${LIKEI_TELEGRAM_MONITOR_PROXY_HOST}
proxy-port: 7897 proxy-port: ${LIKEI_TELEGRAM_MONITOR_PROXY_PORT}
yomi: yomi:
aes_key: Lt2tYDHewn6U4 aes_key: ${LIKEI_YOMI_AES_KEY}

View File

@ -2,9 +2,9 @@ dataSources:
wallet: wallet:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.Driver driverClassName: com.mysql.jdbc.Driver
jdbcUrl: jdbc:p6spy:mysql://mysql:3306/likei_wallet?characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&autoReconnect=true jdbcUrl: ${LIKEI_WALLET_MYSQL_JDBC_URL}
username: root username: ${LIKEI_MYSQL_USERNAME}
password: 123456 password: ${LIKEI_MYSQL_PASSWORD}
#hikari: #hikari:
# 连接池名称 # 连接池名称

View File

@ -1,5 +1,5 @@
spring: spring:
security: security:
user: user:
name: dxxop name: ${LIKEI_VISUAL_MONITOR_USERNAME}
password: devxx23 password: ${LIKEI_VISUAL_MONITOR_PASSWORD}

View File

@ -1,13 +1,14 @@
package com.red.circle.mq.business.model.event.gift; package com.red.circle.mq.business.model.event.gift;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.math.BigDecimal;
import lombok.Data; import java.util.List;
import lombok.EqualsAndHashCode; import lombok.Data;
import lombok.experimental.Accessors; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/** /**
* 游戏幸运礼物抽奖. * 游戏幸运礼物抽奖.
@ -42,13 +43,33 @@ public class GameLuckyGiftBusinessEvent implements Serializable {
/** /**
* 来源系统. * 来源系统.
*/ */
private String sysOrigin; private String sysOrigin;
/** /**
* 礼物id. * 整个送礼动作业务id.
*/ */
@JsonSerialize(using = ToStringSerializer.class) private String businessId;
private Long giftId;
/**
* 扣款资产流水id.
*/
private String consumeAssetRecordId;
/**
* 礼物id.
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long giftId;
/**
* 礼物单价.
*/
private BigDecimal giftPrice;
/**
* 是否免费礼物.
*/
private Boolean giftIsFree;
/** /**
* 选的礼物数量. * 选的礼物数量.

View File

@ -1,34 +1,53 @@
package com.red.circle.gateway.service.impl; package com.red.circle.gateway.service.impl;
import com.red.circle.framework.core.request.RequestHeaderConstant; import com.red.circle.framework.core.request.RequestHeaderConstant;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.gateway.constant.ApiConstant; import com.red.circle.gateway.constant.ApiConstant;
import com.red.circle.gateway.service.AuthEndpointService; import com.red.circle.gateway.service.AuthEndpointService;
import com.red.circle.gateway.service.UserCredential; import com.red.circle.gateway.service.UserCredential;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono; import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
/** import reactor.core.publisher.Mono;
* @author pengliang on 2023/5/5
*/ /**
@Service * @author pengliang on 2023/5/5
@RequiredArgsConstructor */
public class AuthEndpointServiceImpl implements AuthEndpointService { @Service
@RequiredArgsConstructor
private final WebClient.Builder webClientBuilder; public class AuthEndpointServiceImpl implements AuthEndpointService {
@Override private final WebClient.Builder webClientBuilder;
public Mono<ResultResponse<UserCredential>> getTokenCredential(
String authorization) { @Value("${FEIGN_AUTH_URL:}")
return webClientBuilder.build().get() private String authBaseUrl;
.uri(ApiConstant.AUTH_FULL_URL)
.header(RequestHeaderConstant.AUTHORIZATION, authorization) @Override
.retrieve() public Mono<ResultResponse<UserCredential>> getTokenCredential(
.bodyToMono(new ParameterizedTypeReference<>() { String authorization) {
}); return webClientBuilder.build().get()
} .uri(buildTokenCheckUrl())
.header(RequestHeaderConstant.AUTHORIZATION, authorization)
} .retrieve()
.bodyToMono(new ParameterizedTypeReference<>() {
});
}
private String buildTokenCheckUrl() {
String normalizedBaseUrl = authBaseUrl == null ? "" : authBaseUrl.trim();
if (normalizedBaseUrl.isEmpty()) {
return ApiConstant.AUTH_FULL_URL;
}
if (normalizedBaseUrl.endsWith("/")) {
normalizedBaseUrl = normalizedBaseUrl.substring(0, normalizedBaseUrl.length() - 1);
}
return UriComponentsBuilder.fromUriString(normalizedBaseUrl)
.path("/token/check")
.build(true)
.toUriString();
}
}

View File

@ -42,6 +42,7 @@ public class ResidentRegisterRewardServiceImpl implements ResidentRegisterReward
return result.setConfigured(Boolean.TRUE) return result.setConfigured(Boolean.TRUE)
.setEnabled(Boolean.TRUE.equals(config.getEnabled())) .setEnabled(Boolean.TRUE.equals(config.getEnabled()))
.setGoldAmount(defaultGoldAmount(config.getGoldAmount())) .setGoldAmount(defaultGoldAmount(config.getGoldAmount()))
.setDailyLimit(defaultDailyLimit(config.getDailyLimit()))
.setRewardGroupId(config.getRewardGroupId()) .setRewardGroupId(config.getRewardGroupId())
.setRewardGroupName(getRewardGroupName(config.getRewardGroupId())); .setRewardGroupName(getRewardGroupName(config.getRewardGroupId()));
} }
@ -62,6 +63,7 @@ public class ResidentRegisterRewardServiceImpl implements ResidentRegisterReward
config.setSysOrigin(normalizedSysOrigin) config.setSysOrigin(normalizedSysOrigin)
.setEnabled(Boolean.TRUE.equals(cmd.getEnabled())) .setEnabled(Boolean.TRUE.equals(cmd.getEnabled()))
.setGoldAmount(defaultGoldAmount(cmd.getGoldAmount())) .setGoldAmount(defaultGoldAmount(cmd.getGoldAmount()))
.setDailyLimit(defaultDailyLimit(cmd.getDailyLimit()))
.setRewardGroupId(cmd.getRewardGroupId()); .setRewardGroupId(cmd.getRewardGroupId());
if (exists) { if (exists) {
@ -84,6 +86,7 @@ public class ResidentRegisterRewardServiceImpl implements ResidentRegisterReward
private void validateConfig(ResidentRegisterRewardConfigSaveCmd cmd) { private void validateConfig(ResidentRegisterRewardConfigSaveCmd cmd) {
long goldAmount = defaultGoldAmount(cmd.getGoldAmount()); long goldAmount = defaultGoldAmount(cmd.getGoldAmount());
long dailyLimit = defaultDailyLimit(cmd.getDailyLimit());
if (Boolean.TRUE.equals(cmd.getEnabled())) { if (Boolean.TRUE.equals(cmd.getEnabled())) {
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"At least one reward is required when enabled.", "At least one reward is required when enabled.",
@ -92,6 +95,9 @@ public class ResidentRegisterRewardServiceImpl implements ResidentRegisterReward
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"goldAmount must be greater than or equal to zero.", "goldAmount must be greater than or equal to zero.",
goldAmount >= 0); goldAmount >= 0);
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
"dailyLimit must be greater than or equal to zero.",
dailyLimit >= 0);
} }
private String normalizeSysOrigin(String sysOrigin) { private String normalizeSysOrigin(String sysOrigin) {
@ -102,6 +108,10 @@ public class ResidentRegisterRewardServiceImpl implements ResidentRegisterReward
return goldAmount == null ? 0L : goldAmount; return goldAmount == null ? 0L : goldAmount;
} }
private Long defaultDailyLimit(Long dailyLimit) {
return dailyLimit == null ? 0L : dailyLimit;
}
private String getRewardGroupName(Long rewardGroupId) { private String getRewardGroupName(Long rewardGroupId) {
if (rewardGroupId == null) { if (rewardGroupId == null) {
return null; return null;

View File

@ -28,4 +28,9 @@ public class ResidentRegisterRewardConfigCO extends ClientObject {
private Long rewardGroupId; private Long rewardGroupId;
private String rewardGroupName; private String rewardGroupName;
/**
* 每日奖励份数上限0 表示不限
*/
private Long dailyLimit = 0L;
} }

View File

@ -26,4 +26,9 @@ public class ResidentRegisterRewardConfigSaveCmd implements Serializable {
private Long goldAmount; private Long goldAmount;
private Long rewardGroupId; private Long rewardGroupId;
/**
* 每日奖励份数上限0 表示不限
*/
private Long dailyLimit;
} }

View File

@ -36,4 +36,7 @@ public class ResidentRegisterRewardConfig extends TimestampBaseEntity {
@TableField("reward_group_id") @TableField("reward_group_id")
private Long rewardGroupId; private Long rewardGroupId;
@TableField("daily_limit")
private Long dailyLimit;
} }

View File

@ -0,0 +1,52 @@
package com.red.circle.other.adapter.app.debug;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent;
import com.red.circle.other.app.common.gift.LuckyGiftGoClient;
import com.red.circle.other.app.listener.GameLuckyGiftBusinessListener;
import com.red.circle.tool.core.text.StringUtils;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Profile;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Profile("local")
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/internal/debug/lucky-gift", produces = MediaType.APPLICATION_JSON_VALUE)
public class LuckyGiftLocalDebugController {
private final GameLuckyGiftBusinessListener gameLuckyGiftBusinessListener;
@PostMapping("/business-event")
public LuckyGiftGoClient.LuckyGiftGoDrawResponse replayBusinessEvent(
@RequestBody GameLuckyGiftBusinessEvent event) {
validateEvent(event);
LuckyGiftGoClient.LuckyGiftGoDrawResponse response =
gameLuckyGiftBusinessListener.processLotteryEvent(event);
if (response == null) {
throw new IllegalStateException("Lucky gift business event returned empty response");
}
return response;
}
@PostMapping("/go-draw")
public LuckyGiftGoClient.LuckyGiftGoDrawResponse replayGoDrawOnly(
@RequestBody GameLuckyGiftBusinessEvent event) {
validateEvent(event);
return gameLuckyGiftBusinessListener.drawWithGo(event);
}
private void validateEvent(GameLuckyGiftBusinessEvent event) {
if (StringUtils.isBlank(event.getBusinessId())) {
throw new IllegalArgumentException("businessId required");
}
if (Objects.isNull(event.getUsers()) || event.getUsers().isEmpty()) {
throw new IllegalArgumentException("users required");
}
}
}

View File

@ -15,15 +15,16 @@ import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
import com.red.circle.other.inner.asserts.GiftErrorCode; import com.red.circle.other.inner.asserts.GiftErrorCode;
import com.red.circle.other.inner.asserts.OtherErrorCode; import com.red.circle.other.inner.asserts.OtherErrorCode;
import com.red.circle.other.inner.asserts.RoomErrorCode; import com.red.circle.other.inner.asserts.RoomErrorCode;
import com.red.circle.other.inner.enums.material.GiftCurrencyType; import com.red.circle.other.inner.enums.material.GiftCurrencyType;
import com.red.circle.other.inner.enums.material.GiftTabEnum; import com.red.circle.other.inner.enums.material.GiftTabEnum;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO; import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.LocalDateTimeUtils; import com.red.circle.tool.core.date.LocalDateTimeUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient; import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd; import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO; import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin; import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -63,32 +64,55 @@ public class LuckyGiftGiveCmdExe {
Objects.equals(giftConfig.getGiftTab(), GiftTabEnum.MAGIC.name())); Objects.equals(giftConfig.getGiftTab(), GiftTabEnum.MAGIC.name()));
// 过滤赠送人非法值 // 过滤赠送人非法值
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
CollectionUtils.isNotEmpty(cmd.filterAcceptUserId())); CollectionUtils.isNotEmpty(cmd.filterAcceptUserId()));
if (giftConfig.getGiftCandy().equals(new BigDecimal("0.00"))) { boolean luckyGift = GiftTabEnum.LUCKY_GIFT.name().equals(giftConfig.getGiftTab());
BigDecimal dollarAmount = walletGoldClient.getBalance(cmd.requiredReqUserId()).getBody().getDollarAmount(); boolean magicGift = GiftTabEnum.MAGIC.name().equals(giftConfig.getGiftTab());
log.info("赠送幸运礼物金额为0,余额为 {}", dollarAmount); boolean freeGift = giftConfig.getGiftCandy().compareTo(BigDecimal.ZERO) == 0;
return dollarAmount; String businessId = IdWorkerUtils.getIdStr();
}
if (magicGift) {
if (GiftTabEnum.MAGIC.name().equals(giftConfig.getGiftTab())) { ResponseAssert.isFalse(GiftErrorCode.MAGIC_GIFT_QUANTITY_ERROR, cmd.getQuantity() > 1);
ResponseAssert.isFalse(GiftErrorCode.MAGIC_GIFT_QUANTITY_ERROR, cmd.getQuantity() > 1); }
}
WalletReceiptResDTO receipt = null;
// 付钱 BigDecimal balance;
WalletReceiptResDTO receipt = consumeCandy(cmd, giftConfig); if (freeGift) {
balance = walletGoldClient.getBalance(cmd.requiredReqUserId()).getBody().getDollarAmount();
// 礼物处理mq 魔法礼物不处理放到中奖后处理 log.info("赠送幸运礼物金额为0,余额为 {}", balance);
if (!GiftTabEnum.MAGIC.name().equals(giftConfig.getGiftTab())) { if (!luckyGift) {
giftMqMessage.sendGift(receipt.getAssetRecordId().toString(), return balance;
giftAppConvertor.toGiveAwayGiftBatchEvent(cmd, giftConfig, receipt.getAssetRecordId())); }
} } else {
receipt = consumeCandy(cmd, giftConfig);
// 抽奖mq balance = receipt.getBalance().getDollarAmount();
gameLuckyGiftCommon.sendMq(cmd, giftConfig.getStandardId()); }
userProfileGateway.removeCache(cmd.requiredReqUserId()); // 礼物处理mq 魔法礼物不处理放到中奖后处理
if (!magicGift) {
Long trackId = Objects.nonNull(receipt) ? receipt.getAssetRecordId() : Long.parseLong(businessId);
giftMqMessage.sendGift(
Objects.toString(trackId),
giftAppConvertor.toGiveAwayGiftBatchEvent(cmd, giftConfig, trackId)
);
}
// 抽奖mq
if (luckyGift) {
gameLuckyGiftCommon.sendMq(
cmd,
giftConfig.getStandardId(),
businessId,
Objects.nonNull(receipt) ? Objects.toString(receipt.getAssetRecordId()) : null,
giftConfig.getGiftCandy(),
freeGift
);
} else {
gameLuckyGiftCommon.sendMq(cmd, giftConfig.getStandardId());
}
userProfileGateway.removeCache(cmd.requiredReqUserId());
// 检查是否未完成任务 // 检查是否未完成任务
Boolean taskStatus = taskService.checkTaskStatus(cmd.getReqUserId(), 8L, null); Boolean taskStatus = taskService.checkTaskStatus(cmd.getReqUserId(), 8L, null);
@ -100,8 +124,8 @@ public class LuckyGiftGiveCmdExe {
.build()); .build());
} }
return receipt.getBalance().getDollarAmount(); return balance;
} }
/** /**
* 付钱. * 付钱.

View File

@ -133,11 +133,11 @@ public class GameLuckyGiftCommon {
/** /**
* 发送幸运礼物抽奖mq. * 发送幸运礼物抽奖mq.
*/ */
public void sendMq(GiveAwayGiftBatchCmd cmd, Long standardId) { public void sendMq(GiveAwayGiftBatchCmd cmd, Long standardId) {
GameLuckyGiftBusinessEvent event = buildLuckyGiftBusinessEvent(cmd, standardId); GameLuckyGiftBusinessEvent event = buildLuckyGiftBusinessEvent(cmd, standardId);
if (Objects.isNull(event)) { if (Objects.isNull(event)) {
return; return;
} }
event.setUsers(cmd.filterAcceptUserId().stream().map(acceptUserId -> event.setUsers(cmd.filterAcceptUserId().stream().map(acceptUserId ->
@ -154,9 +154,47 @@ public class GameLuckyGiftCommon {
.topic(FixedTopic.RC_DEFAULT_APP_ORDINARY) .topic(FixedTopic.RC_DEFAULT_APP_ORDINARY)
.tag(GameLuckyGiftBusinessSink.TAG) .tag(GameLuckyGiftBusinessSink.TAG)
.body(event) .body(event)
.build()); .build());
} }
public void sendMq(
GiveAwayGiftBatchCmd cmd,
Long standardId,
String businessId,
String consumeAssetRecordId,
BigDecimal giftPrice,
Boolean giftIsFree
) {
GameLuckyGiftBusinessEvent event = new GameLuckyGiftBusinessEvent()
.setBusinessId(businessId)
.setConsumeAssetRecordId(consumeAssetRecordId)
.setUserId(cmd.requiredReqUserId())
.setRoomId(cmd.getRoomId())
.setSysOrigin(cmd.requireReqSysOrigin())
.setGiftId(cmd.getGiftId())
.setGiftPrice(giftPrice)
.setGiftIsFree(Boolean.TRUE.equals(giftIsFree))
.setQuantity(cmd.getQuantity())
.setCheckCombo(cmd.getCheckCombo())
.setGiftCombos(0)
.setStandardId(standardId)
.setUsers(cmd.filterAcceptUserId().stream().map(acceptUserId ->
new GameLuckyGiftUser()
.setId(IdWorkerUtils.getId())
.setAcceptUserId(acceptUserId)
.setGiftsCount(0)
.setComboLossCount(0)
).collect(Collectors.toList()));
senderService.sendEventMessage(MessageEvent.builder()
.consumeId(businessId)
.topic(FixedTopic.RC_DEFAULT_APP_ORDINARY)
.tag(GameLuckyGiftBusinessSink.TAG)
.body(event)
.build());
}
private Integer getComboLossCount(GameLuckyGiftBusinessEvent event) { private Integer getComboLossCount(GameLuckyGiftBusinessEvent event) {

View File

@ -0,0 +1,111 @@
package com.red.circle.other.app.common.gift;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.red.circle.other.infra.config.LuckyGiftGoConfig;
import java.util.List;
import java.util.Objects;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class LuckyGiftGoClient {
private final LuckyGiftGoConfig luckyGiftGoConfig;
public LuckyGiftGoDrawResponse draw(LuckyGiftGoDrawRequest request) {
if (!luckyGiftGoConfig.isEnabled()) {
throw new IllegalStateException("Lucky gift go client is disabled");
}
String baseUrl = Objects.toString(luckyGiftGoConfig.getBaseUrl(), "").trim();
if (baseUrl.isEmpty()) {
throw new IllegalStateException("Lucky gift go baseUrl is blank");
}
HttpResponse response = HttpUtil.createPost(baseUrl + "/internal/lucky-gift/draw")
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("X-Internal-Token", Objects.toString(luckyGiftGoConfig.getInternalToken(), ""))
.timeout(Objects.requireNonNullElse(luckyGiftGoConfig.getTimeoutMillis(), 10000))
.body(JSON.toJSONString(request))
.execute();
String responseBody = response.body();
if (response.getStatus() < 200 || response.getStatus() >= 300) {
throw new IllegalStateException("Lucky gift go http error, status=" + response.getStatus()
+ ", body=" + responseBody);
}
if (responseBody == null || responseBody.trim().isEmpty()) {
throw new IllegalStateException("Lucky gift go response is empty");
}
JSONObject root = JSON.parseObject(responseBody);
if (root == null) {
throw new IllegalStateException("Lucky gift go response is invalid");
}
if (root.containsKey("status") && !root.getBooleanValue("status")) {
throw new IllegalStateException("Lucky gift go business error: " + root.getString("message"));
}
JSONObject body = root.getJSONObject("body");
LuckyGiftGoDrawResponse result = Objects.nonNull(body)
? body.toJavaObject(LuckyGiftGoDrawResponse.class)
: root.toJavaObject(LuckyGiftGoDrawResponse.class);
if (result == null || result.getBusinessId() == null || result.getResults() == null) {
throw new IllegalStateException("Lucky gift go response body is invalid: " + responseBody);
}
return result;
}
@Data
@Accessors(chain = true)
public static class LuckyGiftGoDrawRequest {
private String businessId;
private String consumeAssetRecordId;
private String sysOrigin;
private Long standardId;
private Long roomId;
private Long sendUserId;
private Long giftId;
private Long giftPrice;
private Long giftNum;
private Boolean giftIsFree;
private List<LuckyGiftGoDrawOrder> orders;
}
@Data
@Accessors(chain = true)
public static class LuckyGiftGoDrawOrder {
private String id;
private Long acceptUserId;
}
@Data
@Accessors(chain = true)
public static class LuckyGiftGoDrawResponse {
private String businessId;
private Integer providerCode;
private Long rewardTotal;
private Long balanceAfter;
private List<LuckyGiftGoDrawResult> results;
}
@Data
@Accessors(chain = true)
public static class LuckyGiftGoDrawResult {
private String id;
private String orderId;
private Long acceptUserId;
private Boolean isWin;
private Long rewardNum;
}
}

View File

@ -0,0 +1,224 @@
package com.red.circle.other.app.common.gift;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.external.inner.model.cmd.message.CustomGroupMsgBodyCmd;
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftUser;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.game.GameLuckyGiftMsgCO;
import com.red.circle.other.app.dto.cmd.task.RoomDailyTaskProgressUpdateCmd;
import com.red.circle.other.app.service.task.RoomDailyTaskProgressService;
import com.red.circle.other.app.util.DateTimeAsiaRiyadhUtils;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.game.GameLuckyGiftCount;
import com.red.circle.other.infra.database.rds.entity.live.RoomMember;
import com.red.circle.other.infra.database.rds.service.game.GameLuckyGiftCountService;
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
import com.red.circle.other.inner.enums.material.PropsCommodityType;
import com.red.circle.other.inner.enums.task.RoomDailyTaskCode;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.model.dto.user.props.UserPropsResourcesDTO;
import com.red.circle.other.inner.model.dto.user.props.UserUsePropsDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class LuckyGiftResultProcessor {
private final GameLuckyGiftCountService gameLuckyGiftCountService;
private final GiftCacheService giftCacheService;
private final UserProfileGateway userProfileGateway;
private final UserProfileAppConvertor userProfileAppConvertor;
private final ImGroupClient imGroupClient;
private final RoomDailyTaskProgressService roomDailyTaskProgressService;
private final RoomMemberService roomMemberService;
private final RedisService redisService;
private final RoomProfileManagerService roomProfileManagerService;
private final GameLuckyGiftCommon gameLuckyGiftCommon;
public void process(GameLuckyGiftBusinessEvent event, LuckyGiftGoClient.LuckyGiftGoDrawResponse response) {
GiftConfigDTO giftConfig = giftCacheService.getById(event.getGiftId());
if (giftConfig == null) {
throw new IllegalStateException("Lucky gift config not found, giftId=" + event.getGiftId());
}
UserProfileDTO sendUserProfile = userProfileAppConvertor.toUserProfileDTO(
userProfileGateway.getByUserId(event.getUserId()));
if (sendUserProfile == null) {
throw new IllegalStateException("Lucky gift sender profile not found, userId=" + event.getUserId());
}
Map<String, GameLuckyGiftUser> userMap = Optional.ofNullable(event.getUsers())
.orElse(Collections.emptyList())
.stream()
.collect(Collectors.toMap(user -> Objects.toString(user.getId()), Function.identity()));
if (userMap.size() != Optional.ofNullable(response.getResults()).orElse(Collections.emptyList()).size()) {
throw new IllegalStateException("Lucky gift result size mismatch, businessId=" + event.getBusinessId());
}
UserPropsResourcesDTO avatarFrame = getUserAvatarFrameProps(sendUserProfile);
long payAmount = resolvePayAmount(event, giftConfig);
BigDecimal balanceAfter = BigDecimal.valueOf(Objects.requireNonNullElse(response.getBalanceAfter(), 0L));
for (LuckyGiftGoClient.LuckyGiftGoDrawResult result : response.getResults()) {
GameLuckyGiftUser user = userMap.get(result.getId());
if (user == null) {
throw new IllegalStateException("Lucky gift user mapping missing, resultId=" + result.getId());
}
long rewardNum = Objects.requireNonNullElse(result.getRewardNum(), 0L);
int multiple = payAmount > 0 && rewardNum > 0 ? (int) (rewardNum / payAmount) : 0;
gameLuckyGiftCountService.saveOrUpdate(new GameLuckyGiftCount()
.setId(Long.valueOf(result.getId()))
.setGiftId(event.getGiftId())
.setRoomId(event.getRoomId())
.setQuantity(event.getQuantity())
.setUserId(event.getUserId())
.setSysOrigin(event.getSysOrigin())
.setGiftIncCount(0)
.setGiftCombos(Objects.requireNonNullElse(event.getGiftCombos(), 0))
.setGiftCover(giftConfig.getGiftPhoto())
.setPayAmount(payAmount)
.setMultiple(multiple)
.setChangeInventory(false)
.setSysGiftIncCount(0)
.setAwardAmount(rewardNum)
.setRegionCode(event.getRegionCode())
.setDateNumber(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())
);
if (rewardNum <= 0) {
continue;
}
sendLuckyGiftMessage(event, giftConfig, sendUserProfile, avatarFrame, result, multiple, balanceAfter);
updateRoomDailyTask(event.getUserId(), event.getRoomId(), rewardNum, RoomDailyTaskCode.PERSONAL_LUCKY_GIFT_GOLD);
}
}
private long resolvePayAmount(GameLuckyGiftBusinessEvent event, GiftConfigDTO giftConfig) {
BigDecimal giftPrice = Objects.nonNull(event.getGiftPrice()) ? event.getGiftPrice() : giftConfig.getGiftCandy();
return giftPrice.multiply(BigDecimal.valueOf(Objects.requireNonNullElse(event.getQuantity(), 0))).longValue();
}
private void sendLuckyGiftMessage(
GameLuckyGiftBusinessEvent event,
GiftConfigDTO giftConfig,
UserProfileDTO sendUserProfile,
UserPropsResourcesDTO avatarFrame,
LuckyGiftGoClient.LuckyGiftGoDrawResult result,
Integer multiple,
BigDecimal balanceAfter
) {
GameLuckyGiftMsgCO giftMsg = new GameLuckyGiftMsgCO()
.setSysOrigin(event.getSysOrigin())
.setRoomId(event.getRoomId())
.setRoomAccount(event.getRoomAccount())
.setSendUserId(event.getUserId())
.setAccount(sendUserProfile.actualAccount())
.setNickname(sendUserProfile.getUserNickname())
.setUserAvatar(sendUserProfile.getUserAvatar())
.setAvatarFrameCover(avatarFrame.getCover())
.setAvatarFrameSvg(avatarFrame.getSourceUrl())
.setMultiple(multiple)
.setAwardAmount(result.getRewardNum())
.setGiftId(event.getGiftId())
.setMultipleType(gameLuckyGiftCommon.getRewardMultipleType(multiple))
.setGiftCover(giftConfig.getGiftPhoto())
.setRegionCode(event.getRegionCode())
.setGiftQuantity(event.getQuantity())
.setAcceptUserId(result.getAcceptUserId())
.setAcceptNickname(resolveAcceptNickname(result.getAcceptUserId()))
.setBalance(balanceAfter)
.setGiftCandy(Objects.nonNull(event.getGiftPrice()) ? event.getGiftPrice() : giftConfig.getGiftCandy())
.setGlobalNews(Boolean.TRUE);
imGroupClient.sendMessageBroadcast(
BroadcastGroupMsgBodyCmd.builder()
.toPlatform(SysOriginPlatformEnum.toEnum(giftMsg.getSysOrigin()))
.type(GroupMessageTypeEnum.GAME_LUCKY_GIFT)
.data(giftMsg)
.build()
);
if (StringUtils.isBlank(giftMsg.getRoomAccount())) {
return;
}
imGroupClient.sendCustomMessage(giftMsg.getRoomAccount(),
CustomGroupMsgBodyCmd.builder()
.type(GroupMessageTypeEnum.GAME_LUCKY_GIFT)
.data(giftMsg)
.build());
}
private String resolveAcceptNickname(Long acceptUserId) {
if (acceptUserId == null) {
return null;
}
return Optional.ofNullable(userProfileGateway.getByUserId(acceptUserId))
.map(profile -> profile.getUserNickname())
.orElse(null);
}
private void updateRoomDailyTask(Long userId, Long roomId, Long rewardAmount, RoomDailyTaskCode taskType) {
RoomMember roomMember = roomMemberService.getRoomMember(roomId, userId);
if (roomMember == null) {
return;
}
RoomProfileManager profileManager = roomProfileManagerService.getByUserId(userId);
if (profileManager == null || Objects.equals(profileManager.getId(), roomMember.getRoomId())) {
return;
}
String redisKey = "room:daily:task:progress:" + taskType.name() + ":" + userId + ":"
+ ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
Long total = redisService.increment(redisKey, rewardAmount);
redisService.expire(redisKey, DateTimeAsiaRiyadhUtils.getSecondsUntilMidnight(), TimeUnit.SECONDS);
roomDailyTaskProgressService.updateTaskProgress(
new RoomDailyTaskProgressUpdateCmd()
.setUserId(userId)
.setTaskCode(taskType.name())
.setProgressValue(total.intValue())
);
}
private UserPropsResourcesDTO getUserAvatarFrameProps(UserProfileDTO sendUserProfile) {
if (CollectionUtils.isEmpty(sendUserProfile.getUseProps())) {
return new UserPropsResourcesDTO();
}
return Optional.ofNullable(sendUserProfile.getUseProps().stream()
.filter(props -> Objects.nonNull(props.getPropsResources())
&& !Objects.equals(props.getPropsResources().getType(), PropsCommodityType.AVATAR_FRAME.name())
&& props.getExpireTime() > TimestampUtils.now().getTime())
.findFirst().orElse(new UserUsePropsDTO())
.getPropsResources()).orElse(new UserPropsResourcesDTO());
}
}

View File

@ -1,23 +1,27 @@
package com.red.circle.other.app.listener; package com.red.circle.other.app.listener;
import com.red.circle.component.mq.MessageEventProcess; import com.red.circle.component.mq.MessageEventProcess;
import com.red.circle.component.mq.MessageEventProcessDescribe; import com.red.circle.component.mq.MessageEventProcessDescribe;
import com.red.circle.component.mq.config.RocketMqMessageListener; import com.red.circle.component.mq.config.RocketMqMessageListener;
import com.red.circle.component.mq.service.Action; import com.red.circle.component.mq.service.Action;
import com.red.circle.component.mq.service.ConsumerMessage; import com.red.circle.component.mq.service.ConsumerMessage;
import com.red.circle.component.mq.service.MessageListener; import com.red.circle.component.mq.service.MessageListener;
import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent; import com.red.circle.mq.business.model.event.gift.GameLuckyGiftBusinessEvent;
import com.red.circle.mq.rocket.business.streams.GameLuckyGiftBusinessSink; import com.red.circle.mq.rocket.business.streams.GameLuckyGiftBusinessSink;
import com.red.circle.other.app.common.gift.GameLuckyGiftCommon; import com.red.circle.other.app.common.gift.GameLuckyGiftCommon;
import com.red.circle.other.app.common.gift.GameLuckyGiftParamCmd; import com.red.circle.other.app.common.gift.LuckyGiftGoClient;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; import com.red.circle.other.app.common.gift.LuckyGiftResultProcessor;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile; import com.red.circle.other.app.common.gift.GameLuckyGiftParamCmd;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.tool.core.date.LocalDateTimeUtils; import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import java.util.Objects; import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import lombok.RequiredArgsConstructor; import com.red.circle.tool.core.text.StringUtils;
import lombok.extern.slf4j.Slf4j; import com.red.circle.tool.core.date.LocalDateTimeUtils;
import java.util.stream.Collectors;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/** /**
* 游戏幸运礼物抽奖. * 游戏幸运礼物抽奖.
@ -29,13 +33,15 @@ import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GameLuckyGiftBusinessListener implements MessageListener { public class GameLuckyGiftBusinessListener implements MessageListener {
private final UserRegionGateway userRegionGateway; private final UserRegionGateway userRegionGateway;
private final MessageEventProcess messageEventProcess; private final MessageEventProcess messageEventProcess;
private final GameLuckyGiftCommon gameLuckyGiftManager; private final GameLuckyGiftCommon gameLuckyGiftManager;
private final RoomProfileManagerService roomProfileManagerService; private final RoomProfileManagerService roomProfileManagerService;
private final LuckyGiftGoClient luckyGiftGoClient;
private final LuckyGiftResultProcessor luckyGiftResultProcessor;
@Override @Override
public Action consume(ConsumerMessage message) { public Action consume(ConsumerMessage message) {
return messageEventProcess.consume( return messageEventProcess.consume(
MessageEventProcessDescribe.builder() MessageEventProcessDescribe.builder()
@ -47,48 +53,77 @@ public class GameLuckyGiftBusinessListener implements MessageListener {
.message(message) .message(message)
.build(), .build(),
GameLuckyGiftBusinessEvent.class, GameLuckyGiftBusinessEvent.class,
this::processLottery); this::processLottery);
} }
/** /**
* 保存幸运礼物流水. * 保存幸运礼物流水.
*/ */
private void processLottery(GameLuckyGiftBusinessEvent event) { private void processLottery(GameLuckyGiftBusinessEvent event) {
processLotteryEvent(event);
if (Objects.isNull(event.getRoomId())) { }
return;
} public LuckyGiftGoClient.LuckyGiftGoDrawResponse processLotteryEvent(GameLuckyGiftBusinessEvent event) {
if (Objects.isNull(event.getRoomId())) {
long startTime = LocalDateTimeUtils.nowEpochMilli(); log.warn("Lucky gift event missing roomId, businessId={}", event.getBusinessId());
return null;
try { }
RoomProfile roomProfile = roomProfileManagerService.getProfileById(event.getRoomId());
if (Objects.isNull(roomProfile)) { long startTime = LocalDateTimeUtils.nowEpochMilli();
return;
} try {
RoomProfile roomProfile = roomProfileManagerService.getProfileById(event.getRoomId());
GameLuckyGiftParamCmd cmd = buildLuckyGiftRunParam(event, roomProfile); if (Objects.nonNull(roomProfile)) {
event.setRoomAccount(roomProfile.getRoomAccount());
event.getUsers().forEach(user -> { } else if (StringUtils.isBlank(event.getBusinessId())) {
log.warn("Lucky gift room profile missing for legacy flow, roomId={}", event.getRoomId());
cmd.setId(user.getId()); return null;
cmd.setGiftsCount(user.getGiftsCount()); } else {
cmd.setAcceptUserId(user.getAcceptUserId()); log.warn("Lucky gift room profile missing, continue go draw with fallback roomAccount, businessId={}, roomId={}",
cmd.setComboLossCount(user.getComboLossCount()); event.getBusinessId(), event.getRoomId());
gameLuckyGiftManager.run(cmd); }
});
} finally { if (StringUtils.isBlank(event.getRegionCode())) {
long endTime = LocalDateTimeUtils.nowEpochMilli() - startTime; event.setRegionCode(userRegionGateway.getRegionCode(event.getUserId()));
if (endTime > (1000 * 20)) { }
log.warn("[游戏幸运礼物抽奖] 队列处理耗时:{}", endTime);
} if (StringUtils.isBlank(event.getBusinessId())) {
} GameLuckyGiftParamCmd cmd = buildLuckyGiftRunParam(event, roomProfile);
event.getUsers().forEach(user -> {
} cmd.setId(user.getId());
cmd.setGiftsCount(user.getGiftsCount());
private GameLuckyGiftParamCmd buildLuckyGiftRunParam(GameLuckyGiftBusinessEvent event, cmd.setAcceptUserId(user.getAcceptUserId());
RoomProfile roomProfile) { cmd.setComboLossCount(user.getComboLossCount());
return new GameLuckyGiftParamCmd() gameLuckyGiftManager.run(cmd);
});
return null;
}
LuckyGiftGoClient.LuckyGiftGoDrawResponse response = drawWithGo(event);
luckyGiftResultProcessor.process(event, response);
return response;
} finally {
long endTime = LocalDateTimeUtils.nowEpochMilli() - startTime;
if (endTime > (1000 * 20)) {
log.warn("[游戏幸运礼物抽奖] 队列处理耗时:{}", endTime);
}
}
}
public LuckyGiftGoClient.LuckyGiftGoDrawResponse drawWithGo(GameLuckyGiftBusinessEvent event) {
LuckyGiftGoClient.LuckyGiftGoDrawResponse response = luckyGiftGoClient.draw(buildGoRequest(event));
if (!Objects.equals(event.getBusinessId(), response.getBusinessId())) {
throw new IllegalStateException("Lucky gift businessId mismatch, request=" + event.getBusinessId()
+ ", response=" + response.getBusinessId());
}
log.info("Lucky gift go draw success businessId={}, standardId={}, providerCode={}, rewardTotal={}",
event.getBusinessId(), event.getStandardId(), response.getProviderCode(), response.getRewardTotal());
return response;
}
private GameLuckyGiftParamCmd buildLuckyGiftRunParam(GameLuckyGiftBusinessEvent event,
RoomProfile roomProfile) {
return new GameLuckyGiftParamCmd()
.setUserId(event.getUserId()) .setUserId(event.getUserId())
.setRoomId(event.getRoomId()) .setRoomId(event.getRoomId())
.setRoomAccount(roomProfile.getRoomAccount()) .setRoomAccount(roomProfile.getRoomAccount())
@ -101,9 +136,28 @@ public class GameLuckyGiftBusinessListener implements MessageListener {
.setSysComboLoss(event.getSysComboLoss()) .setSysComboLoss(event.getSysComboLoss())
.setOpenGiftGiveTotal(event.getOpenGiftGiveTotal()) .setOpenGiftGiveTotal(event.getOpenGiftGiveTotal())
.setSysGiftGiveTotal(event.getSysGiftGiveTotal()) .setSysGiftGiveTotal(event.getSysGiftGiveTotal())
.setRegionCode(userRegionGateway.getRegionCode(event.getUserId())) .setRegionCode(userRegionGateway.getRegionCode(event.getUserId()))
.setStandardId(event.getStandardId()); .setStandardId(event.getStandardId());
} }
private LuckyGiftGoClient.LuckyGiftGoDrawRequest buildGoRequest(GameLuckyGiftBusinessEvent event) {
} return new LuckyGiftGoClient.LuckyGiftGoDrawRequest()
.setBusinessId(event.getBusinessId())
.setConsumeAssetRecordId(event.getConsumeAssetRecordId())
.setSysOrigin(event.getSysOrigin())
.setStandardId(event.getStandardId())
.setRoomId(event.getRoomId())
.setSendUserId(event.getUserId())
.setGiftId(event.getGiftId())
.setGiftPrice(Objects.nonNull(event.getGiftPrice()) ? event.getGiftPrice().longValue() : 0L)
.setGiftNum(Objects.nonNull(event.getQuantity()) ? Long.valueOf(event.getQuantity()) : 0L)
.setGiftIsFree(Boolean.TRUE.equals(event.getGiftIsFree()))
.setOrders(event.getUsers().stream().map(user ->
new LuckyGiftGoClient.LuckyGiftGoDrawOrder()
.setId(Objects.toString(user.getId(), null))
.setAcceptUserId(user.getAcceptUserId())
).collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,21 @@
package com.red.circle.other.infra.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "lucky.gift.go")
public class LuckyGiftGoConfig {
private boolean enabled = true;
private String baseUrl;
private String internalToken;
private Integer timeoutMillis = 10000;
}

View File

@ -80,14 +80,16 @@ public class RegionConfigClientServiceImpl implements RegionConfigClientService
} }
@Override @Override
public void add(SysRegionCmd config) { public void add(SysRegionCmd config) {
config.setId(IdWorkerUtils.getIdStr()); config.setId(IdWorkerUtils.getIdStr());
ResponseAssert.isFalse(UserErrorCode.CODE_ALREADY_EXISTS, ResponseAssert.isFalse(UserErrorCode.CODE_ALREADY_EXISTS,
sysRegionConfigService.existRegionCode(config.getRegionCode(), config.getId(), config.getSysOrigin())); sysRegionConfigService.existRegionCode(config.getRegionCode(), config.getId(), config.getSysOrigin()));
sysRegionConfigService.add(regionConfigInnerConvertor.toSysRegionConfig(config)); SysRegionConfig regionConfig = regionConfigInnerConvertor.toSysRegionConfig(config);
regionCacheService.remove(config.getSysOrigin()); regionConfig.setWithdrawalWays(StringUtils.join(config.getWithdrawalWaysList(), ","));
} sysRegionConfigService.add(regionConfig);
regionCacheService.remove(config.getSysOrigin());
}
@Override @Override
public void update(SysRegionCmd config) { public void update(SysRegionCmd config) {

View File

@ -3,13 +3,13 @@ logging:
com.red.circle.*: debug com.red.circle.*: debug
com.alibaba.cloud.nacos.*: debug com.alibaba.cloud.nacos.*: debug
feign: feign:
gateway: gateway:
url: http://127.0.0.1:1100 url: http://127.0.0.1:1100
wallet: wallet:
url: http://127.0.0.1:2000 url: http://wallet:2000
other: other:
url: http://127.0.0.1:2400 url: http://127.0.0.1:2400
live: live:
url: http://127.0.0.1:2500 url: http://127.0.0.1:2500
console: console:
@ -19,4 +19,4 @@ feign:
order: order:
url: http://127.0.0.1:2600 url: http://127.0.0.1:2600
external: external:
url: http://127.0.0.1:3000 url: http://127.0.0.1:3000

View File

@ -3,6 +3,11 @@ package com.red.circle.framework.shardingsphere.driver;
import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
@ -40,12 +45,6 @@ public class NacosDriverURLProvider implements ShardingSphereDriverURLProvider {
} }
Map<String, String> queryParams = parseQuery(url); Map<String, String> queryParams = parseQuery(url);
Properties properties = new Properties();
setIfHasText(properties, "serverAddr", queryParams.get("serverAddr"));
setIfHasText(properties, "namespace", queryParams.get("namespace"));
setIfHasText(properties, "username", queryParams.get("username"));
setIfHasText(properties, "password", queryParams.get("password"));
String group = Optional.ofNullable(queryParams.get(GROUP)) String group = Optional.ofNullable(queryParams.get(GROUP))
.filter(NacosDriverURLProvider::hasText) .filter(NacosDriverURLProvider::hasText)
.orElse("DEFAULT_GROUP"); .orElse("DEFAULT_GROUP");
@ -57,19 +56,95 @@ public class NacosDriverURLProvider implements ShardingSphereDriverURLProvider {
shardingConfigFilename, shardingConfigFilename,
group, group,
queryParams); queryParams);
ConfigService configService = NacosFactory.createConfigService(properties); String content = "";
String content = configService.getConfig(shardingConfigFilename, group, TIMEOUT_MILLIS); try {
content = loadConfig(queryParams, shardingConfigFilename, group, true);
} catch (NacosException ex) {
LOGGER.warn(
"Load sharding config via nacos client failed, fallback to HTTP. dataId={}, group={}",
shardingConfigFilename,
group,
ex);
}
if (!hasText(content)) {
LOGGER.warn(
"Empty sharding config via nacos client, fallback to HTTP. dataId={}, group={}",
shardingConfigFilename,
group);
content = loadConfigViaHTTP(queryParams, shardingConfigFilename, group);
}
if (!hasText(content)) { if (!hasText(content)) {
throw new RuntimeException( throw new RuntimeException(
"Empty Nacos sharding config: dataId=" + shardingConfigFilename + ", group=" + group); "Empty Nacos sharding config: dataId=" + shardingConfigFilename + ", group=" + group);
} }
LOGGER.info(content); LOGGER.info(content);
return content.getBytes(StandardCharsets.UTF_8); return content.getBytes(StandardCharsets.UTF_8);
} catch (NacosException ex) { } catch (IOException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
private String loadConfig(Map<String, String> queryParams, String dataID, String group,
boolean includeAuth) throws NacosException {
ConfigService configService = NacosFactory.createConfigService(
buildProperties(queryParams, includeAuth));
return configService.getConfig(dataID, group, TIMEOUT_MILLIS);
}
private String loadConfigViaHTTP(Map<String, String> queryParams, String dataID, String group)
throws IOException {
String serverAddr = queryParams.get("serverAddr");
if (!hasText(serverAddr)) {
return "";
}
StringBuilder urlBuilder = new StringBuilder("http://")
.append(serverAddr)
.append("/nacos/v1/cs/configs?dataId=")
.append(encode(dataID))
.append("&group=")
.append(encode(group));
String namespace = queryParams.get("namespace");
if (hasText(namespace) && !"public".equalsIgnoreCase(namespace.trim())) {
urlBuilder.append("&tenant=").append(encode(namespace));
}
HttpURLConnection connection = (HttpURLConnection) new URL(urlBuilder.toString()).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout((int) TIMEOUT_MILLIS);
connection.setReadTimeout((int) TIMEOUT_MILLIS);
int status = connection.getResponseCode();
if (status != HttpURLConnection.HTTP_OK) {
LOGGER.warn(
"Load sharding config via HTTP failed. status={}, dataId={}, group={}, url={}",
status,
dataID,
group,
urlBuilder);
return "";
}
try (InputStream inputStream = connection.getInputStream()) {
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
} finally {
connection.disconnect();
}
}
private Properties buildProperties(Map<String, String> queryParams, boolean includeAuth) {
Properties properties = new Properties();
setIfHasText(properties, "serverAddr", queryParams.get("serverAddr"));
setIfHasText(properties, "namespace", queryParams.get("namespace"));
if (includeAuth) {
setIfHasText(properties, "username", queryParams.get("username"));
setIfHasText(properties, "password", queryParams.get("password"));
}
return properties;
}
private static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
private static void setIfHasText(Properties properties, String key, String value) { private static void setIfHasText(Properties properties, String key, String value) {
if (hasText(value)) { if (hasText(value)) {
properties.setProperty(key, value); properties.setProperty(key, value);