diff --git a/.env b/.env new file mode 100644 index 0000000..e92f9ee --- /dev/null +++ b/.env @@ -0,0 +1,86 @@ +APP_BIND=0.0.0.0 +APP_PORT=2026 +DEFAULT_REFRESH_INTERVAL_SECONDS=10 +REFRESH_INTERVAL_OPTIONS=5,10,15,30,60 +PROBE_TIMEOUT_SECONDS=3 +PROBE_CACHE_TTL_SECONDS=5 +PROBE_MAX_WORKERS=12 +HOST_METRIC_CACHE_TTL_SECONDS=25 +TAT_METRIC_TIMEOUT_SECONDS=30 +TAT_CPU_SAMPLE_SECONDS=1 +NACOS_BASE_URL=http://10.2.1.17:8848 +NACOS_NAMESPACE_ID=f7a8594e-090c-4830-a3ad-b5c0f9afcc07 +NACOS_NAMESPACE_NAME=RedCircleServiceProd +NACOS_DISCOVERY_GROUP=prod +NACOS_DISCOVERY_CLUSTER_NAME=DEFAULT +NACOS_CACHE_TTL_SECONDS=15 +MONGO_URI=mongodb://root:123456@10.2.21.9:27017/tarab_all?authSource=admin&readPreference=secondaryPreferred&retryWrites=false&maxPoolSize=50&minPoolSize=5&maxIdleTimeMS=6000 +MONGO_DB_NAME=tarab_all +MONGO_INSTANCE_ID=ins-o9mmob66 +MONGO_CACHE_TTL_SECONDS=20 +CPU_WARN_PERCENT=60 +CPU_BAD_PERCENT=85 +MEMORY_WARN_PERCENT=70 +MEMORY_BAD_PERCENT=90 +DISK_WARN_PERCENT=75 +DISK_BAD_PERCENT=90 +PROCESS_WARN_COUNT=180 +PROCESS_BAD_COUNT=260 +SERVICE_LATENCY_WARN_MS=1000 +SERVICE_LATENCY_BAD_MS=3000 +DEPLOY_REGION=me-saudi-arabia +TENCENT_SECRET_ID=IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu +TENCENT_SECRET_KEY=nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl +GATEWAY_CLB_LOAD_BALANCER_ID=lb-cbiabr1q +GATEWAY_CLB_LISTENER_IDS=lbl-ktvz8m6k +GATEWAY_CLB_ALLOWED_DOMAINS=jvapi.haiyihy.com +GATEWAY_CLB_POLL_SECONDS=2 +GATEWAY_CLB_TASK_TIMEOUT_SECONDS=120 +GATEWAY_CLB_DRAIN_SECONDS=0 +CDN_ALLOWED_DOMAINS=h5.haiyihy.com +CDN_PURGE_TASK_LIMIT=20 + +# Admin frontend deployment for Yumi +UPDATE_DEFAULT_ADMIN_GIT_REF=main +ADMIN_FRONTEND_ENABLED=1 +ADMIN_FRONTEND_SERVICE_NAME=admin +ADMIN_FRONTEND_REPO_URL=git@gitea.haiyihy.com:hy/chatapp3-admin.git +ADMIN_FRONTEND_REPO_ROOT=/opt/deploy/sources/chatapp3-admin +ADMIN_FRONTEND_HOST=admin-platform +ADMIN_FRONTEND_IP=10.2.1.2 +ADMIN_FRONTEND_INSTANCE_ID=ins-p11begwe +ADMIN_FRONTEND_SSH_HOST=10.2.1.2 +ADMIN_FRONTEND_SSH_USER=root +ADMIN_FRONTEND_SSH_PORT=22 +ADMIN_FRONTEND_SSH_USE_SUDO=0 +ADMIN_FRONTEND_REMOTE_DIR=/opt/yumi-admin/frontend-admin +ADMIN_FRONTEND_SITE_DIR=/opt/yumi-admin/frontend-admin/site +ADMIN_FRONTEND_COMPOSE_FILE=/opt/yumi-admin/frontend-admin/docker-compose.yml +ADMIN_FRONTEND_COMPOSE_SERVICE=caddy +ADMIN_FRONTEND_RELEASE_META_PATH=/opt/yumi-admin/frontend-admin/.hy-app-monitor-admin-release.json +ADMIN_FRONTEND_BUILD_SCRIPT=build:antdv-next +ADMIN_FRONTEND_DIST_DIR=apps/dist +ADMIN_FRONTEND_PUBLIC_URL=https://yumi-admin.haiyihy.com +CHATAPP_CRON_ENABLED=1 +CHATAPP_CRON_REPO_URL=git@gitea.haiyihy.com:hy/chatapp-cron.git +CHATAPP_CRON_REPO_ROOT=/opt/deploy/sources/chatapp-cron +CHATAPP_CRON_DEFAULT_GIT_REF=main +CHATAPP_CRON_SERVICE_NAME=chatapp-cron +CHATAPP_CRON_HOST=cron +CHATAPP_CRON_IP=10.3.1.14 +CHATAPP_CRON_INSTANCE_ID=ins-nt6bsay0 +CHATAPP_CRON_SSH_HOST=10.3.1.14 +CHATAPP_CRON_SSH_USER=root +CHATAPP_CRON_SSH_PORT=22 +CHATAPP_CRON_SSH_USE_SUDO=0 +CHATAPP_CRON_REMOTE_DIR=/opt/deploy/runtime/current +CHATAPP_CRON_COMPOSE_FILE=/opt/deploy/runtime/current/docker-compose.yml +CHATAPP_CRON_COMPOSE_SERVICE=week-star-job +CHATAPP_CRON_BINARY_PATH=/opt/deploy/runtime/current/week-star-job/service +CHATAPP_CRON_RELEASE_META_PATH=/opt/deploy/runtime/current/.hy-app-monitor-chatapp-cron-release.json + +# Harbor credentials for hy-app-monitor service update +HARBOR_REGISTRY=10.2.1.3:18082 +HARBOR_PROJECT=likei +HARBOR_USERNAME=admin +HARBOR_PASSWORD=QkVXKcxCff_3x-pEkDCR_aAB diff --git a/.gitignore b/.gitignore index 11f89e7..77683c5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ run/ __pycache__/ *.pyc .DS_Store -.env .venv/ diff --git a/localbox/.env.local b/localbox/.env.local new file mode 100644 index 0000000..48ab087 --- /dev/null +++ b/localbox/.env.local @@ -0,0 +1,399 @@ +# +# Baishun source profiles. +# Keep the current compatibility vars below unchanged until the switch script lands. +# +BAISHUN_ACTIVE_PROFILE=prod + +# Golang / new baishun integration +BAISHUN_GOLANG_TEST_PLATFORM_BASE_URL=https://game-cn-test.jieyou.shop +BAISHUN_GOLANG_TEST_APP_ID=4581045902 +BAISHUN_GOLANG_TEST_APP_NAME=yumiparty_app +BAISHUN_GOLANG_TEST_APP_CHANNEL=yumiparty +BAISHUN_GOLANG_TEST_APP_KEY=jHpYp5sNMvHHfn3dhaPQhkCTL8SYMXVy +BAISHUN_GOLANG_TEST_GSP=101 +BAISHUN_GOLANG_TEST_LAUNCH_CODE_TTL_SECONDS=300 +BAISHUN_GOLANG_TEST_SS_TOKEN_TTL_SECONDS=86400 +BAISHUN_GOLANG_PROD_PLATFORM_BASE_URL=https://mesh-channels-online.jieyou.shop +BAISHUN_GOLANG_PROD_APP_ID=7485318192 +BAISHUN_GOLANG_PROD_APP_NAME=yumiparty_app +BAISHUN_GOLANG_PROD_APP_CHANNEL=yumiparty +BAISHUN_GOLANG_PROD_APP_KEY=i1PUKj0aJjdWF3qRbBeoGBEgfFsHpUGS +BAISHUN_GOLANG_PROD_GSP=111 +BAISHUN_GOLANG_PROD_LAUNCH_CODE_TTL_SECONDS=300 +BAISHUN_GOLANG_PROD_SS_TOKEN_TTL_SECONDS=86400 + +# Java other / lucky gift baishun integration +BAISHUN_JAVA_TEST_APP_ID=1704692112 +BAISHUN_JAVA_TEST_APP_CHANNEL=lotfun +BAISHUN_JAVA_TEST_APP_KEY=6EllbAruJDfw +BAISHUN_JAVA_TEST_LUCKY_GIFT_API_CONFIG_1_STANDARD_ID=18816 +BAISHUN_JAVA_TEST_LUCKY_GIFT_API_CONFIG_1_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +BAISHUN_JAVA_TEST_LUCKY_GIFT_API_CONFIG_2_STANDARD_ID=18816 +BAISHUN_JAVA_TEST_LUCKY_GIFT_API_CONFIG_2_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +BAISHUN_JAVA_TEST_LUCKY_GIFT_API_DEFAULT_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +BAISHUN_JAVA_PROD_APP_ID=7485318192 +BAISHUN_JAVA_PROD_APP_CHANNEL=yumiparty +BAISHUN_JAVA_PROD_APP_KEY=i1PUKj0aJjdWF3qRbBeoGBEgfFsHpUGS +BAISHUN_JAVA_PROD_LUCKY_GIFT_API_CONFIG_1_STANDARD_ID=18816 +BAISHUN_JAVA_PROD_LUCKY_GIFT_API_CONFIG_1_URL=https://mesh-channels-online.jieyou.shop/lucky_gift/start_game +BAISHUN_JAVA_PROD_LUCKY_GIFT_API_CONFIG_2_STANDARD_ID=18816 +BAISHUN_JAVA_PROD_LUCKY_GIFT_API_CONFIG_2_URL=https://mesh-channels-online.jieyou.shop/lucky_gift/start_game +BAISHUN_JAVA_PROD_LUCKY_GIFT_API_DEFAULT_URL=https://mesh-channels-online.jieyou.shop/lucky_gift/start_game + +# Current active compatibility values +BAISHUN_APP_CHANNEL=yumiparty +BAISHUN_APP_ID=7485318192 +BAISHUN_APP_KEY=i1PUKj0aJjdWF3qRbBeoGBEgfFsHpUGS +BAISHUN_APP_NAME=yumiparty_app +BAISHUN_PLATFORM_BASE_URL=https://mesh-channels-online.jieyou.shop +BAISHUN_GSP=111 +BAISHUN_LAUNCH_CODE_TTL_SECONDS=300 +BAISHUN_SS_TOKEN_TTL_SECONDS=86400 +CHATAPP_AUTO_MIGRATE=false +CHATAPP_HTTP_SHUTDOWN_TIMEOUT_SECONDS=30 +CHATAPP_HTTP_TIMEOUT_SECONDS=8 +CHATAPP_JAVA_AUTH_BASE_URL=http://auth:1000 +CHATAPP_JAVA_CONSOLE_BASE_URL=http://console:2700/console +CHATAPP_JAVA_APP_BASE_URL=http://other:2400 +CHATAPP_JAVA_DEVICE_BASE_URL=http://other:2400 +CHATAPP_JAVA_EXTERNAL_BASE_URL=http://external:3000 +CHATAPP_JAVA_OTHER_BASE_URL=http://other:2400 +CHATAPP_JAVA_WALLET_BASE_URL=http://wallet:2000 +CHATAPP_STORE_MYSQL_DSN=root:123456@tcp(mysql:3306)/likei?charset=utf8mb4&parseTime=True&loc=Asia%2FRiyadh +CHATAPP_STORE_REDIS_ADDR=redis:6379 +CHATAPP_STORE_REDIS_DB=0 +CHATAPP_STORE_REDIS_PASSWORD="" +CHATAPP_WEEK_STAR_DEFAULT_SYS_ORIGIN=LIKEI +CHATAPP_WEEK_STAR_RETRY_BATCH_SIZE=10 +CHATAPP_WEEK_STAR_RETRY_BLOCK_MILLIS=5000 +CHATAPP_WEEK_STAR_RETRY_CONSUMER_GROUP=week-star-retry +CHATAPP_WEEK_STAR_RETRY_CONSUMER_NAME=week-star-retry-cron-sg-1 +CHATAPP_WEEK_STAR_RETRY_MIN_IDLE_MILLIS=60000 +CHATAPP_WEEK_STAR_RETRY_STREAM_KEY=week-star:reward-retry +CHATAPP_WEEK_STAR_SETTLE_INTERVAL_SECONDS=60 +CHATAPP_WEEK_STAR_TIMEZONE=Asia/Riyadh +CRON_AUTO_MIGRATE=false +CRON_HTTP_TIMEOUT_SECONDS=8 +CRON_JAVA_OTHER_BASE_URL=http://10.2.1.16:2400 +CRON_MYSQL_DSN=root:123456@tcp(mysql:3306)/likei?charset=utf8mb4&parseTime=True&loc=Asia%2FRiyadh +CRON_REDIS_ADDR=redis:6379 +CRON_REDIS_DB=0 +CRON_REDIS_PASSWORD="" +CRON_SHUTDOWN_TIMEOUT_SECONDS=30 +GAME_INTERNAL_CALLBACK_SECRET=dNIiHptGHkDs8ngMoK_1XCTRxzzTGb19 +GAME_JAVA_WALLET_BASE_URL=http://wallet:2000 +GAME_LUCKY_GIFT_GO_URL=http://golang:2900 +INVITE_CAMPAIGN_GO_URL=http://golang:2900 +GITEA_ADMIN_PASSWORD="A59chf#33" +GITEA_ADMIN_USERNAME=admin +GITEA_BASE_URL=http://43.164.74.132:3000 +LIKEI_AGORA_APP_CERTIFICATE=a6feb209de6448148a926f59634807bb +LIKEI_AGORA_APP_ID="" +LIKEI_AGORA_AUTH_KEY="Basic ZTA0MTVjMzYwZjBmNDNhZGFhNTdjZDZmNjgwYTFiZWQ6MWIyYmNjZDU0NGQzNDRhYmJhMTNiNDliZjUyMGY4MTI=" +LIKEI_AGORA_PRIVILEGE_EXPIRE_SECOND=86400 +LIKEI_AGORA_TOKEN_EXPIRE_SECOND=86400 +LIKEI_AIRWALLEX_API_KEY=e397fa14297xxxxxxxx6d3dff3e92c63c338 +LIKEI_AIRWALLEX_BASE_URL=https://api-demo.airwallex.com +LIKEI_AIRWALLEX_CLIENT_ID=j5v_C5xxg +LIKEI_AI_MINIMAX_AUTHORIZATION="Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiJ0b255IGxpdSIsIlVzZXJOYW1lIjoidG9ueSBsaXUiLCJBY2NvdW50IjoiIiwiU3ViamVjdElEIjoiMTkzMDg0MzI0Nzg4NjczMzY4NCIsIlBob25lIjoiIiwiR3JvdXBJRCI6IjE5MzA4NDMyNDc4ODI1MzkzODAiLCJQYWdlTmFtZSI6IiIsIk1haWwiOiJsaXV0YW90b255M0BpY2xvdWQuY29tIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDYtMjUgMTQ6MzA6MjYiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.TAHcSE-3YSSLWC9z9424GVF6twqi3Po5LkpGENtLF25397IvEV-CiXDFzBE5F-H6w9yG-YAROwGy0jFxwoDWPF4IsC2emKp5Qan5geavx7YqTEUQ4vJzhu7TJgDrvvUcUanVPQRBo5IyqpPuDagNPHhmPca7wgOrVHQfahUs7Q5VwOUiUDguHdwXcl6h4Yk32Ufv7rHDuS_sZnuAXxG_dY_XfIkJGwdMz7O7c9uWICnnMFXAL7GEyhy50MKJoEiCFLWnIC6Tu20oTnd2QBDlp1JCzdphA9FpBqo0SVCSmR2CZK1Uo4oXioxizkfv4EgPpCZUkOVSqT2f74l1zbFe-g" +LIKEI_AI_MINIMAX_MODEL=MiniMax-Text-01 +LIKEI_AI_MINIMAX_URL=https://api.minimax.io/v1/text/chatcompletion_v2 +LIKEI_AI_QIANFAN_APP_ID="" +LIKEI_AI_QIANFAN_AUTHORIZATION="Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiJ0b255IGxpdSIsIlVzZXJOYW1lIjoidG9ueSBsaXUiLCJBY2NvdW50IjoiIiwiU3ViamVjdElEIjoiMTkzMDg0MzI0Nzg4NjczMzY4NCIsIlBob25lIjoiIiwiR3JvdXBJRCI6IjE5MzA4NDMyNDc4ODI1MzkzODAiLCJQYWdlTmFtZSI6IiIsIk1haWwiOiJsaXV0YW90b255M0BpY2xvdWQuY29tIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDYtMjUgMTQ6MzA6MjYiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.TAHcSE-3YSSLWC9z9424GVF6twqi3Po5LkpGENtLF25397IvEV-CiXDFzBE5F-H6w9yG-YAROwGy0jFxwoDWPF4IsC2emKp5Qan5geavx7YqTEUQ4vJzhu7TJgDrvvUcUanVPQRBo5IyqpPuDagNPHhmPca7wgOrVHQfahUs7Q5VwOUiUDguHdwXcl6h4Yk32Ufv7rHDuS_sZnuAXxG_dY_XfIkJGwdMz7O7c9uWICnnMFXAL7GEyhy50MKJoEiCFLWnIC6Tu20oTnd2QBDlp1JCzdphA9FpBqo0SVCSmR2CZK1Uo4oXioxizkfv4EgPpCZUkOVSqT2f74l1zbFe-g" +LIKEI_AI_QIANFAN_MODEL=MiniMax-Text-01 +LIKEI_AI_QIANFAN_URL=https://api.minimax.io/v1/text/chatcompletion_v2 +LIKEI_AI_TTS_MODEL=MiniMax-Text-01 +LIKEI_AI_TTS_URL=https://api.minimax.io/v1/text/chatcompletion_v2 +LIKEI_ALIYUN_OSS_ACCESS_KEY_ID=LTAI5 +LIKEI_ALIYUN_OSS_ACCESS_KEY_SECRET=v2Z31d +LIKEI_ALIYUN_OSS_ACCESS_URL=https://media.haiyihy.com +LIKEI_ALIYUN_OSS_BUCKET_NAME=tkm-likei +LIKEI_ALIYUN_OSS_ENDPOINT=http://oss-accelerate.aliyuncs.com +LIKEI_ALIYUN_STS_ENDPOINT=sts.us-west-1.aliyuncs.com +LIKEI_ALIYUN_STS_ROLE_ARN=acs:ram::124470563:role/stsoss +LIKEI_APP_INTERNAL_LB_ID=lb-epvnr4o0 +LIKEI_APP_INTERNAL_LB_VIP=10.2.1.16 +LIKEI_ARTIFACT_DELIVERY_MODE=direct-http +LIKEI_ARTIFACT_HTTP_PORT=18080 +LIKEI_CENSOR_ACTIVE=qcloud +LIKEI_CENSOR_TUPU_ENABLED=true +LIKEI_CLB_SUBNET_ID=subnet-c0uzemts +LIKEI_CLIPSPAY_MD5_SECRET_KEY=18455c7xxxxx4a48fb7fe +LIKEI_CLIPSPAY_MERCHANT_NO=800xx2370 +LIKEI_CLIPSPAY_NOTIFY_URL=https://dexxxxx.com/play/server/notice/clipspay +LIKEI_CLIPSPAY_PLACE_ORDER_API=http://uat.card.api.clipspay.com/payment/gateway/api/backTransReq +LIKEI_CLIPSPAY_REDIRECT_RESULT=https://dev.xxxxine.com/clipspay/redirect +LIKEI_CLIPSPAY_TERMINAL_KEY=NzMyNGRxxxxxYThiMmE4ODA +LIKEI_CLIPSPAY_TERMINAL_NO=10xxx6 +LIKEI_CLOUD_MONGO_DB=tarab_all +LIKEI_CLOUD_MONGO_HOST=10.2.21.9 +LIKEI_CLOUD_MONGO_PORT=27017 +LIKEI_CLOUD_MONGO_PROXY_PORT=37017 +LIKEI_CLOUD_MONGO_URI=mongodb://root:123456@10.2.21.9:27017/tarab_all?authSource=admin&readPreference=secondaryPreferred&retryWrites=false&maxPoolSize=50&minPoolSize=5&maxIdleTimeMS=6000 +LIKEI_CLOUD_MYSQL_DATABASES="likei likei_wallet" +LIKEI_CLOUD_MYSQL_HOST=10.2.21.3 +LIKEI_CLOUD_MYSQL_PASSWORD="A59chf#33" +LIKEI_CLOUD_MYSQL_PORT=3306 +LIKEI_CLOUD_MYSQL_PROXY_PORT=33306 +LIKEI_CLOUD_MYSQL_USER=root +LIKEI_DEFAULT_DEPLOY_ORDER_JSON=["mongo-1","nacos-2","nacos-1","app-2","pay-2","gateway-2","app-1","pay-1","gateway-1","cron-sg-1"] +LIKEI_DEPLOY_BASE_DIR=/opt/deploy +LIKEI_DEPLOY_BUCKET=haiyihy-deploy-1420526837 +LIKEI_DEPLOY_BUCKET_REGION=me-saudi-arabia +LIKEI_DEPLOY_CONNECTION_DRAIN_POLL_SECONDS=2 +LIKEI_DEPLOY_CONNECTION_DRAIN_TIMEOUT_SECONDS=20 +LIKEI_DEPLOY_HOSTS_JSON={"nacos-1":{"ip":"10.2.22.2","instance_id":"ins-3yelqb7y","services":["nacos"],"group":"nacos"},"nacos-2":{"ip":"10.2.22.10","instance_id":"ins-0oxyvn58","services":["nacos"],"group":"nacos"},"mongo-1":{"ip":"10.2.21.9","instance_id":"ins-o9mmob66","services":["mongo"],"group":"infra"},"app-1":{"ip":"10.2.11.3","instance_id":"ins-n566mmeg","services":["auth","external","console","other","live","golang"],"group":"app"},"app-2":{"ip":"10.2.12.6","instance_id":"ins-kauk17la","services":["auth","external","console","other","live","golang"],"group":"app"},"pay-1":{"ip":"10.2.11.14","instance_id":"ins-ceqfcxd2","services":["wallet","order"],"group":"pay"},"pay-2":{"ip":"10.2.12.5","instance_id":"ins-awhb74q6","services":["wallet","order"],"group":"pay"},"gateway-1":{"ip":"10.2.1.8","instance_id":"ins-aeyaoj40","services":["gateway"],"group":"gateway"},"gateway-2":{"ip":"10.2.2.17","instance_id":"ins-irvi5b7u","services":["gateway"],"group":"gateway"},"cron-sg-1":{"ip":"10.3.1.14","instance_id":"ins-nt6bsay0","services":["week-star-job"],"group":"cron","region":"ap-singapore"}} +LIKEI_DEPLOY_LB_DRAIN_SETTLE_SECONDS=8 +LIKEI_DEPLOY_MACHINE_INSTANCE_ID=ins-ntmpcd3a +LIKEI_DEPLOY_MACHINE_TAT_REGION=me-saudi-arabia +LIKEI_DEPLOY_REGION=me-saudi-arabia +LIKEI_DEPLOY_REPO_REF=main +LIKEI_DEPLOY_RUNTIME_ROOT=/opt/deploy/runtime/current +LIKEI_DEPLOY_SOURCES_ROOT=/opt/deploy/sources +LIKEI_DEPLOY_STATE_ROOT=/opt/deploy/state +LIKEI_DEPLOY_STOP_TIMEOUT_SECONDS=45 +LIKEI_EXTERNAL_LOCAL_DISK_READ_COMPAT=false +LIKEI_EXTERNAL_OSS_MODE=tencent-cos +LIKEI_FRAMEWORK_NACOS_STOP_KEY=CxILm9hA1b9hF3Hl +LIKEI_FRONTEND_ADMIN_CONSOLE_UPSTREAM=10.2.1.16:2700 +LIKEI_FRONTEND_ADMIN_DOMAIN=yumi-admin.haiyihy.com +LIKEI_FRONTEND_ADMIN_GOLANG_UPSTREAM=10.2.1.16:2900 +LIKEI_FRONTEND_ADMIN_INSTANCE_ID=ins-p11begwe +LIKEI_GAME_BAISHUN2FUN_APP_CHANNEL=lotfun +LIKEI_GAME_BAISHUN2FUN_APP_ID=1704692112 +LIKEI_GAME_BAISHUN2FUN_APP_KEY=6EllbAruJDfw +LIKEI_GAME_BAISHUN_APP_CHANNEL=yumiparty +LIKEI_GAME_BAISHUN_APP_ID=7485318192 +LIKEI_GAME_BAISHUN_APP_KEY=i1PUKj0aJjdWF3qRbBeoGBEgfFsHpUGS +LIKEI_GAME_HKYS_SIGN_KEY=svO +LIKEI_GAME_HOTGAME_SIGN_KEY=svO +LIKEI_GAME_SUD_APP_CHANNEL=lotfun +LIKEI_GAME_SUD_APP_ID=1704692112 +LIKEI_GAME_SUD_APP_KEY=6EllbAruJDfw +LIKEI_GAME_SUD_APP_SECRET=Psw9s7nOnxxxxxxxS97y4uf0vW +LIKEI_GATEWAY_CLB_ID=lb-cbiabr1q +LIKEI_GATEWAY_FORWARD_AES_KEY=8NcSaTt8EHjRlRuG +LIKEI_GATEWAY_FORWARD_ROUTE_AES_KEY=7NcAa111UGiRlRiR +LIKEI_GATEWAY_INTERNAL_LB_VIP=10.2.1.12 +LIKEI_GATEWAY_ROUTE_AUTH_URI=http://auth:1000 +LIKEI_GATEWAY_ROUTE_EXTERNAL_URI=http://external:3000 +LIKEI_GATEWAY_ROUTE_FORWARD_URI=lb://rc-auth +LIKEI_GATEWAY_ROUTE_GAME_APP_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_GAME_BAISHUN_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_GAME_INTERNAL_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_GO_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_INVITE_APP_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_INVITE_INTERNAL_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_INVITE_PUBLIC_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_LIVE_URI=http://live:2500 +LIKEI_GATEWAY_ROUTE_ORDER_URI=http://order:2600 +LIKEI_GATEWAY_ROUTE_OTHER_URI=http://other:2400 +LIKEI_GATEWAY_ROUTE_REGISTER_REWARD_APP_URI=http://golang:2900 +LIKEI_GATEWAY_ROUTE_WALLET_URI=http://wallet:2000 +LIKEI_GOOGLE_PAY_GLOBAL_PATCH_JSON=payfile/google_pay.json +LIKEI_GOOGLE_PAY_GLOBAL_SERVER_ACCOUNT=server-api@api-5499404589076025365-781142.iam.gserviceaccount.com +LIKEI_GOOGLE_PAY_TAXAB_PATCH_JSON=payfile/tarab-427706-04fe535b024a.json +LIKEI_GOOGLE_PAY_TAXAB_PUBLIC_KEY=MIIBIjANxxxxxxxxTjmAO68rmnKr2gYJ3isuepCZsaX0wIDAQAB +LIKEI_GOOGLE_PAY_TAXAB_SERVER_ACCOUNT=tarab-server@tarab-427706.iam.gserviceaccount.com +LIKEI_H5_CDN_PATH=https://h5.haiyihy.com/ +LIKEI_H5_VERIFY_URL=https://h5.haiyihy.com/index.html +LIKEI_HUAWEI_CLIENT_ID=11xx93 +LIKEI_HUAWEI_CLIENT_SECRET=dff36e68xxxx30da9c7240ae0bc96 +LIKEI_HUAWEI_GRANT_TYPE=client_credentials +LIKEI_HUAWEI_IAP_PUBLIC_KEY=MIIBojANBgkqhkiG9w0Bxxxxx7cdmApDJfpAlKeLZ9fy7d3VIWyqZiLYtxxxxj3t+sFuC4lEJBVrw5MgDE7bmpjidOm0rxxxxUYC1hSI8xXagbJ0sOcYXSunxxxx1NaupT2+ILoZPfIQVF4RThlQmphuOif4uMMlYvYosiueCKlv6MYQi0fVcLKEjWVc/XslowtLS4w0EV/eAVpFq7kTvy04LNYVscSjZop7AHEMVVoNgzg+mLC0UGsftYRfEBeKHkNppTg931qodgJSkIM582ZTK0eujAJR43On3z1gc8+UvSKW+9w+tAqw099VYrFY3sXySUfVJ6SoejiHeKlAgMBAAE= +LIKEI_HUAWEI_OAUTH_LOGIN_URL=https://oauth-login.cloud.huawei.com/oauth2/v3/token +LIKEI_IM_APP_ID=20036101 +LIKEI_IM_BASE_ENDPOINT=https://adminapisgp.im.qcloud.com +LIKEI_IM_BROADCAST_GROUP_LIKEI="@TGS#2RUK4PK5C2" +LIKEI_IM_BROADCAST_GROUP_LOTFUN="@TGS#a3C" +LIKEI_IM_IDENTIFIER=yumiadmin +LIKEI_IM_KEY=dcdf53135f27e7cf8541c4ae9798fb0cb2f0e4d6c5c20022dbaea053f35cbb8c +LIKEI_IM_NEWSLETTER_ACCOUNT=yuminotice +LIKEI_IM_NOTICE_ACCOUNT=yuminotice +LIKEI_LIGHTHOUSE_REGION=ap-singapore +LIKEI_LOCALHOST_ASSET_PREFIX=http://127.0.0.1:3000/oss/local/ +LIKEI_LOCAL_ASSET_PREFIX=http://10.0.2.2:3000/oss/local/ +LIKEI_LOCAL_AUTH_PORT=1000 +LIKEI_LOCAL_CONSOLE_PORT=2700 +LIKEI_LOCAL_DATA_SYNC_MODE=direct +LIKEI_LOCAL_EXTERNAL_PORT=3000 +LIKEI_LOCAL_GAME_FRUIT_JAVA_OPTS="-Xms128m -Xmx384m" +LIKEI_LOCAL_GAME_FRUIT_PORT=8001 +LIKEI_LOCAL_GATEWAY_PORT=1100 +LIKEI_LOCAL_GOLANG_PORT=2900 +LIKEI_LOCAL_JAVA_OPTS="-Xms128m -Xmx512m" +LIKEI_LOCAL_LIVE_PORT=2500 +LIKEI_LOCAL_MONGO_CONTAINER=chatapp3-local-mongo +LIKEI_LOCAL_MONGO_EXPOSE_PORT=27018 +LIKEI_LOCAL_MONGO_ROOT_PASSWORD=123456 +LIKEI_LOCAL_MONGO_ROOT_USERNAME=root +LIKEI_LOCAL_MYSQL_CONTAINER=chatapp3-local-mysql +LIKEI_LOCAL_MYSQL_DATABASE=likei +LIKEI_LOCAL_MYSQL_EXPOSE_PORT=13306 +LIKEI_LOCAL_MYSQL_INFRA_EXPOSE_PORT=13306 +LIKEI_LOCAL_MYSQL_ROOT_PASSWORD=123456 +LIKEI_LOCAL_NACOS_AUTH_ENABLE=false +LIKEI_LOCAL_NACOS_CLIENT_GRPC_PORT=9848 +LIKEI_LOCAL_NACOS_CONSOLE_PORT=8080 +LIKEI_LOCAL_NACOS_JVM_XMN=128m +LIKEI_LOCAL_NACOS_JVM_XMS=256m +LIKEI_LOCAL_NACOS_JVM_XMX=256m +LIKEI_LOCAL_NACOS_PORT=8848 +LIKEI_LOCAL_ORDER_PORT=2600 +LIKEI_LOCAL_OTHER_PORT=2400 +LIKEI_LOCAL_REDIS_EXPOSE_PORT=16379 +LIKEI_LOCAL_REDIS_INFRA_EXPOSE_PORT=16379 +LIKEI_LOCAL_ROCKETMQ_IMAGE_TAG=5.3.2 +LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT=19876 +LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT=18081 +LIKEI_LOCAL_ROCKETMQ_PROXY_HTTP_PORT=18080 +LIKEI_LOCAL_SCHEDULING_JAVA_OPTS="-Xms128m -Xmx384m" +LIKEI_LOCAL_SCHEDULING_PORT=2800 +LIKEI_LOCAL_SYNC_CACHE_DIR=/Users/hy/Documents/hy/chatapp3/chatapp3-deploy/tencent-prod/var/cache/local-data-sync +LIKEI_LOCAL_VISUAL_MONITOR_PORT=8000 +LIKEI_LOCAL_WALLET_PORT=2000 +LIKEI_LOCAL_ZOOKEEPER_EXPOSE_PORT=2181 +LIKEI_MAVEN_REPO_LOCAL=/opt/deploy/.m2/repository +LIKEI_MIFA_PAY_GATEWAY_BASE_URL=https://pay-gate-uat.payermax.com +LIKEI_MIFA_PAY_MER_ACCOUNT=d00f5fc97a114a0db291eceaf9841739 +LIKEI_MIFA_PAY_MER_NO=10001925 +LIKEI_MIFA_PAY_NOTIFY_URL=https://jvapi.haiyihy.com/play-server-notice/mifa_pay/receive_payment +LIKEI_MIFA_PAY_PLATFORM_RSA_PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAACBAQ8AMIIBCgKCAQEAi4+8n/BEFhWKzWs1SMdD+1gzK3xiI/wGGTS330yKSxQMM5Ec39AFQjKFTvcjIZegt2vTQYnA/AL0l0O5C98BWSBuM20/pUXd1+i/Ew/lvLYoeKDD4ARkCzJfXQcDgvm4gTZvnVJwerCN+E2rziNZoLTdTo468IArzBVFzWGa/YmQvi7brCbTlzp5EpVeZMNLNpM04I0uJIiqGpEp0PDPbbn/ZVzZLoLKO+LXWxXx1nFPVlL+X1yk1TyJVfPv7Au3mv9UXNGSF6EP21n97aaU1j29+PXNy3Yze8pmkdWmcOqGnORSLPk0Acl6gklBGyvFiSk/QsL1ocecqD8cJk1JbQIDAQAB +LIKEI_MIFA_PAY_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= +LIKEI_MONGO_HOST=10.2.21.9 +LIKEI_MONGO_PORT=27017 +LIKEI_MONGO_URI=mongodb://root:123456@mongo:27017/tarab_all?authSource=admin&readPreference=secondaryPreferred&retryWrites=false&maxPoolSize=50&minPoolSize=5&maxIdleTimeMS=6000 +LIKEI_MYSQL_JDBC_URL=jdbc:p6spy:mysql://mysql:3306/likei?characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&autoReconnect=true +LIKEI_MYSQL_PASSWORD=123456 +LIKEI_MYSQL_SCAN_HOST=app-1 +LIKEI_MYSQL_USERNAME=root +LIKEI_NACOS_CLIENT_GRPC_PORT=9848 +LIKEI_NACOS_DB_NAME=nacos +LIKEI_NACOS_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true +LIKEI_NACOS_DB_PASSWORD="A59chf#33" +LIKEI_NACOS_DB_USER=root +LIKEI_NACOS_DISCOVERY_CACHE_SETTLE_SECONDS=8 +LIKEI_NACOS_DISCOVERY_CLUSTER_NAME=DEFAULT +LIKEI_NACOS_DISCOVERY_DISABLE_TIMEOUT_SECONDS=30 +LIKEI_NACOS_DISCOVERY_ENABLE_TIMEOUT_SECONDS=60 +LIKEI_NACOS_DISCOVERY_GROUP=local +LIKEI_NACOS_DISCOVERY_POLL_SECONDS=2 +LIKEI_NACOS_HOST=10.2.1.17 +LIKEI_NACOS_INTERNAL_LB_ID=lb-6xvx317u +LIKEI_NACOS_INTERNAL_LB_VIP=10.2.1.17 +LIKEI_NACOS_NAMESPACE=f7a8594e-090c-4830-a3ad-b5c0f9afcc07 +LIKEI_NACOS_NAMESPACE_NAME=chatapp3-local +LIKEI_NACOS_PORT=8848 +LIKEI_ORDER_TELEGRAM_BOT_TOKEN=72649:AAE7gZj0 +LIKEI_ORDER_TELEGRAM_WEBHOOK_URL=https://local.api.yuyinfang168.com/order/telegram/webhook +LIKEI_PAYERMAX_APP_ID=d6afddeb3ca447448 +LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE=false +LIKEI_PAYERMAX_GATEWAY_BASE_URL=https://pay-gate-uat.payermax.com +LIKEI_PAYERMAX_MERCHANT_ID=SDP01010 +LIKEI_PAYERMAX_PLATFORM_RSA_PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAACBAQ8AMIIBCgKCAQEAi4+8n/BEFhWKzWs1SMdD+1gzK3xiI/wGGTS330yKSxQMM5Ec39AFQjKFTvcjIZegt2vTQYnA/AL0l0O5C98BWSBuM20/pUXd1+i/Ew/lvLYoeKDD4ARkCzJfXQcDgvm4gTZvnVJwerCN+E2rziNZoLTdTo468IArzBVFzWGa/YmQvi7brCbTlzp5EpVeZMNLNpM04I0uJIiqGpEp0PDPbbn/ZVzZLoLKO+LXWxXx1nFPVlL+X1yk1TyJVfPv7Au3mv9UXNGSF6EP21n97aaU1j29+PXNy3Yze8pmkdWmcOqGnORSLPk0Acl6gklBGyvFiSk/QsL1ocecqD8cJk1JbQIDAQAB +LIKEI_PAYERMAX_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= +LIKEI_PAYERMAX_RSA_PUBLIC_KEY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkFNiYgHUjvDNwkH7eZ2RBizvf0zxQK0An31c1qGs954iGnCfwd3TnjyclzJY7igcqEQvtQKVvvbnFV6LpZC5KlAL3tKu8SjBWsQsODgBJEQuiYY2IBCciVyxAPSkU+hJJb76Jqn1MLnXQirUzSy9oRbRuftj/gYqGK3pGiImYfZSHpdZrJ+FiqAady4MkrXGQUDj84Q+zXCrG6PqaY0+CQUkMlWa3Cd5mHvmElf0J8PymNr9zsz3iwKXmYS4ecFbH3Jss9OCBxaICyI0VRRlOl2738/Lo0baaAQ/t0Us+RiogSz46EoBi0iMQlnNdFaYSsDpb0dG4t7LCmBvR7B8OQIDAQAB +LIKEI_PAYERMAX_SECRET_KEY=8aexx98f +LIKEI_PAYNICORN_APP_KEY=79xx58 +LIKEI_PAYNICORN_MERCHANT_SECRET=704a8xxx50b +LIKEI_PAYPAL_DEV_MERCHANT_ID=Ac2aB2KFgz3xxxxxGmbS7dcPedRf2_eg23D +LIKEI_PAYPAL_DEV_SECRET_KEY=ECjyOP4nxxxxxxB0JEAH9P7im +LIKEI_PAYPAL_MERCHANT_ID=AZm9zUAxxxxx8kiGKL6D4l0elx2 +LIKEI_PAYPAL_SECRET_KEY=EJuYA6cSud6xxxxx4_Fj9rbBh1yYnr97btui2ocuR +LIKEI_PAY_INTERNAL_LB_ID=lb-4f5xi6p0 +LIKEI_PAY_INTERNAL_LB_VIP=10.2.1.15 +LIKEI_PAY_WEB_PAY_BASE_URL="https://h5.likeichat.com/#/" +LIKEI_PAY_WEB_PAY_COLLECTION_PAGE=collection-receipt +LIKEI_PAY_WEB_PAY_RECHARGE_PAGE=recharge +LIKEI_PAY_WEB_PAY_RESULT_PAGE=pay-result +LIKEI_PUBLIC_API_BASE=https://jvapi.haiyihy.com +LIKEI_PUBLIC_H5_DOMAIN=h5.haiyihy.com +LIKEI_PUBLIC_H5_ORIGIN_DOMAIN=h5-origin.haiyihy.com +LIKEI_PUBLIC_ROOT_DOMAIN=haiyihy.com +LIKEI_PUBLIC_SITE_CERT_ID=WkzXsNlm +LIKEI_PUBLIC_SITE_INSTANCE_ID=lhins-0waytx8h +LIKEI_PUBLIC_WWW_DOMAIN=www.haiyihy.com +LIKEI_PUBLIC_WWW_ORIGIN_DOMAIN=www-origin.haiyihy.com +LIKEI_REDIS_DATABASE=0 +LIKEI_REDIS_HOST=redis +LIKEI_REDIS_PORT=6379 +LIKEI_ROCKETMQ_ACCESS_KEY=local +LIKEI_ROCKETMQ_ENDPOINT=rocketmq-proxy:8081 +LIKEI_ROCKETMQ_LOCAL_DISABLE=false +LIKEI_ROCKETMQ_SECRET_KEY=local +LIKEI_RTC_APP_ID=4b5e5cea3b86476caf7f7a57d05b82d1 +LIKEI_RTC_AUTH_KEY="Basic ZTA0MTVjMzYwZjBmNDNhZGFhNTdjZDZmNjgwYTFiZWQ6MWIyYmNjZDU0NGQzNDRhYmJhMTNiNDliZjUyMGY4MTI=" +LIKEI_RTC_CERTIFICATE=a6feb209de6448148a926f59634807bb +LIKEI_RTC_KILL_ROOM_URL=https://api.sd-rtn.com/dev/v1/kicking-rule +LIKEI_SERVICE_STOP_GRACE_PERIOD_SECONDS=45 +LIKEI_SMS_ALIYUN_ACCESS_KEY_ID=LTAI5 +LIKEI_SMS_ALIYUN_ACCESS_KEY_SECRET=v2Z31d +LIKEI_SMS_ALIYUN_ENABLED=true +LIKEI_SMS_ALIYUN_ENDPOINT=http://oss-accelerate.aliyuncs.com +LIKEI_SMS_ALIYUN_SIGN_NAME=Tarab +LIKEI_TAT_IMPORT_INSTANCE_ID=ins-n566mmeg +LIKEI_TAT_MONGO_INSTANCE_ID=ins-o9mmob66 +LIKEI_TAT_MYSQL_INSTANCE_ID=ins-n566mmeg +LIKEI_TAT_REGION=ap-singapore +LIKEI_TELEGRAM_BOT_TOKEN=8350:AAGwh1O +LIKEI_TELEGRAM_MONITOR_ALERT_LIMIT_SECONDS=60 +LIKEI_TELEGRAM_MONITOR_CHAT_ID_1=-5081 +LIKEI_TELEGRAM_MONITOR_PROXY_HOST=127.0.0.1 +LIKEI_TELEGRAM_MONITOR_PROXY_PORT=7897 +LIKEI_TENCENT_CLOUD_IMS_ENDPOINT=http://oss-accelerate.aliyuncs.com +LIKEI_TENCENT_CLOUD_IMS_REGION=me-saudi-arabia +LIKEI_TENCENT_CLOUD_IMS_SECRET_ID=IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu +LIKEI_TENCENT_CLOUD_IMS_SECRET_KEY=nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl +LIKEI_TENCENT_CLS_ENDPOINT=ap-singapore.cls.tencentcs.com +LIKEI_TENCENT_CLS_REGION=ap-singapore +LIKEI_TENCENT_CLS_SECRET_ID=IKID1pNfgOmrc4G8frlNfcEWU7PMkrd4AwNU +LIKEI_TENCENT_CLS_SECRET_KEY=oISIp41i7F6fwvby1kCLBivsWqrZ07vV +LIKEI_TENCENT_COS_ACCESS_URL=https://media.haiyihy.com +LIKEI_TENCENT_COS_BUCKET=yumi-assets-1420526837 +LIKEI_TENCENT_COS_ENABLED=true +LIKEI_TENCENT_COS_REGION=me-saudi-arabia +LIKEI_TENCENT_COS_SECRET_ID=IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu +LIKEI_TENCENT_COS_SECRET_KEY=nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl +LIKEI_TRTC_ENDPOINT=http://oss-accelerate.aliyuncs.com +LIKEI_TRTC_SDK_APP_ID=20036101 +LIKEI_TRTC_SECRET_ID=IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu +LIKEI_TRTC_SECRET_KEY=nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl +LIKEI_VISUAL_MONITOR_PASSWORD=devxx23 +LIKEI_VISUAL_MONITOR_USERNAME=dxxop +LIKEI_VPC_ID=vpc-rdxuns0f +LIKEI_WALLET_MYSQL_JDBC_URL=jdbc:p6spy:mysql://mysql:3306/likei_wallet?characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&autoReconnect=true +LIKEI_YOMI_AES_KEY=Lt2tYDHewn6U4 +LUCKY_GIFT_API_CONFIG_1_STANDARD_ID=18816 +LUCKY_GIFT_API_CONFIG_1_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +LUCKY_GIFT_API_CONFIG_2_STANDARD_ID=18816 +LUCKY_GIFT_API_CONFIG_2_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +LUCKY_GIFT_API_DEFAULT_APP_CHANNEL=lotfun +LUCKY_GIFT_API_DEFAULT_APP_ID=1704692112 +LUCKY_GIFT_API_DEFAULT_APP_KEY=6EllbAruJDfw +LUCKY_GIFT_API_DEFAULT_URL=https://game-cn-test.jieyou.shop/lucky_gift/start_game +LUCKY_GIFT_API_ENABLED=true +LUCKY_GIFT_GO_ENABLED=true +LUCKY_GIFT_GO_TIMEOUT_MILLIS=10000 +NACOS_CONFIG_HOST=127.0.0.1 +NACOS_CONFIG_PORT=8848 +NACOS_CONSOLE_HOST=127.0.0.1 +NACOS_CONSOLE_PORT=8080 +NACOS_HOST=nacos +NACOS_PORT=8848 +NACOS_URL=http://127.0.0.1:8848/nacos +NACOS_USERNAME= +NACOS_PASSWORD= +NAMESPACE_ID=f7a8594e-090c-4830-a3ad-b5c0f9afcc07 +NAMESPACE_NAME=chatapp3-local +TENCENT_SECRET_ID=IKIDMchhZEfrsiNo472DAtTpzzmLjttkOnyu +TENCENT_SECRET_KEY=nMkbLsGRO6ZqulSyJQJ0UjjU0KSKxOgl +TZ=Asia/Shanghai +WEEK_STAR_DEFAULT_SYS_ORIGIN=LIKEI +WEEK_STAR_RETRY_BATCH_SIZE=10 +WEEK_STAR_RETRY_BLOCK_MILLIS=5000 +WEEK_STAR_RETRY_CONSUMER_GROUP=week-star-retry +WEEK_STAR_RETRY_CONSUMER_NAME=week-star-retry-cron-sg-1 +WEEK_STAR_RETRY_MIN_IDLE_MILLIS=60000 +WEEK_STAR_RETRY_STREAM_KEY=week-star:reward-retry +WEEK_STAR_SETTLE_INTERVAL_SECONDS=60 +WEEK_STAR_TIMEZONE=Asia/Riyadh diff --git a/localbox/.gitignore b/localbox/.gitignore new file mode 100644 index 0000000..a3d75a7 --- /dev/null +++ b/localbox/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.venv/ +__pycache__/ +release.env +tmp/ +var/ +*.gz diff --git a/localbox/AGENTS.md b/localbox/AGENTS.md new file mode 100644 index 0000000..5a33900 --- /dev/null +++ b/localbox/AGENTS.md @@ -0,0 +1,25 @@ +# AGENTS Rules + +`localbox部署` 只负责本地部署和本地联调。`chatapp3` 的线上部署已经迁移到 `hy-app-monitor`。 + +## 仓库结构 + +- 仓库根目录保留统一入口 `./deploy.sh` +- 本地脚本和 compose 文件都放在仓库根目录 +- `local-infra/` 只存放本地 MySQL / RocketMQ 初始化文件 +- `.env.local` 放在仓库根目录 +- `var/` 只存放本地缓存和构建产物,不提交到仓库 +- 默认自动识别 `../../chatapp3/chatapp3-java` 和 `../../chatapp3/chatapp3-golang`;路径不同再用环境变量覆盖 + +## 必须遵守 + +- 只使用仓库根目录 `./deploy.sh` 作为推荐入口 +- 本地构建依赖 `chatapp3-java` 和 `chatapp3-golang` sibling 仓库 +- Java 私有 Maven 包只来自 `chatapp3-java/maven_private` +- 所有新增能力都必须服务于本地启动、本地构建、本地检查、本地重启或本地 Nacos 配置发布 + +## 禁止 + +- 禁止重新引入 `gitea/`、`tencent-prod/`、Jenkins、发布控制台、Harbor、远程部署、回滚、云侧同步相关代码 +- 禁止重新引入 `.env.prod`、发布编排、线上 Nacos 发布、TAT、COS 等链路 +- 禁止新增与本地部署无关的目录、脚本或入口 diff --git a/localbox/README.md b/localbox/README.md new file mode 100644 index 0000000..68ecc24 --- /dev/null +++ b/localbox/README.md @@ -0,0 +1,164 @@ +# localbox部署 + +`chatapp3` 的线上部署已经迁移到 `hy-app-monitor`。这个目录只保留本地部署、本地构建、本地检查和本地联调能力。 + +## 目录结构 + +```text +localbox部署/ +├── deploy.sh # 统一入口 +├── start_local_services.sh # 启动本地环境 +├── build_local_backend.sh # 构建本地 Java 后端 +├── restart_local_service.sh # 重启单个服务 +├── check_local_services.sh # 检查本地服务状态 +├── publish_local_nacos_configs.sh +├── local-services.compose.yml # 本地完整环境 compose +├── local-infra.compose.yml # 轻量基础设施 compose +├── local-infra/ # MySQL / RocketMQ 初始化文件 +├── .env.local # 本地环境变量 +└── var/ # 本地缓存和构建产物(已忽略) +``` + +## 前置条件 + +- macOS 已安装 Docker Desktop +- 如需重新编译 Java,当前终端使用 `JDK 17` +- 工作区中存在 `chatapp3-java` 和 `chatapp3-golang` +- 目录根部 `.env.local` 已准备好本地配置 + +脚本会自动识别现有的 `../../chatapp3/chatapp3-java` 和 `../../chatapp3/chatapp3-golang`。如果本地目录不同,可以通过 `LIKEI_WORKSPACE_DIR`、`LIKEI_LOCAL_JAVA_REPO_DIR` 或 `LIKEI_LOCAL_GOLANG_REPO_DIR` 覆盖。 + +## 快速开始 + +推荐统一从 `hy-app-monitor/localbox部署` 目录执行: + +```bash +./deploy.sh start +``` + +如果只想启动、不重新构建本地 Java jar: + +```bash +./deploy.sh start --skip-build +``` + +如果只起基础设施,不起业务服务: + +```bash +./deploy.sh start --infra-only +``` + +如果只想单独起轻量基础设施(MySQL + Redis): + +```bash +docker compose --env-file ./.env.local -f ./local-infra.compose.yml up -d +``` + +## 常用命令 + +重新构建全部 Java 服务: + +```bash +./deploy.sh build +``` + +只构建指定服务: + +```bash +./deploy.sh build auth live other +``` + +检查全部本地服务状态: + +```bash +./deploy.sh check +``` + +重启单个服务: + +```bash +./deploy.sh restart live +./deploy.sh restart golang +./deploy.sh restart mysql +./deploy.sh restart rocketmq +``` + +重新构建并重启某个 Java 服务: + +```bash +./deploy.sh restart --rebuild auth +./deploy.sh restart --rebuild live +``` + +重新发布本地 Nacos 配置: + +```bash +./deploy.sh publish-nacos +``` + +## 启动流程 + +默认启动流程如下: + +1. 安装 `chatapp3-java/maven_private` 私有 Maven 包到本地 Maven 仓库。 +2. 当前终端为 `JDK 17` 时,使用 `local` profile 构建本地 Java jar。 +3. 启动本地 MySQL、Redis、Mongo、Nacos、Zookeeper。 +4. 当 `LIKEI_ROCKETMQ_LOCAL_DISABLE=false` 时,额外启动本地 RocketMQ。 +5. 发布本地 Nacos 配置。 +6. 启动全部 Java 服务和 `chatapp3-golang`。 + +脚本会优先复用当前可用的 Docker Desktop daemon;如果 Docker Desktop 还没起来,会尝试自动拉起。 + +## RocketMQ 开关 + +本地幸运礼物全链路默认可以启用 RocketMQ。开关在目录根部 `.env.local`: + +```bash +LIKEI_ROCKETMQ_LOCAL_DISABLE=false +LIKEI_ROCKETMQ_ENDPOINT=rocketmq-proxy:8081 +``` + +如果只想先把 `other` 跑起来、不走 MQ: + +```bash +LIKEI_ROCKETMQ_LOCAL_DISABLE=true +``` + +脚本会自动给 `other` 补上 `RocketMQAutoConfiguration` 的排除参数。 + +## 常用排查 + +查看 compose 状态: + +```bash +docker compose --env-file ./.env.local -f ./local-services.compose.yml ps +``` + +查看服务日志: + +```bash +docker compose --env-file ./.env.local -f ./local-services.compose.yml logs -f live +docker compose --env-file ./.env.local -f ./local-services.compose.yml logs -f golang +``` + +## 本地端口 + +- `gateway`: `1100` +- `auth`: `1000` +- `wallet`: `2000` +- `other`: `2400` +- `live`: `2500` +- `order`: `2600` +- `console`: `2700` +- `external`: `3000` +- `visual-monitor`: `8000` +- `game-fruit`: `8001` +- `scheduling`: `2800` +- `golang`: `2900` +- `nacos`: `8848` +- `rocketmq namesrv`: `19876` +- `rocketmq proxy http`: `18080` +- `rocketmq proxy grpc`: `18081` +- `mysql`: `13306` +- `redis`: `16379` +- `mongo`: `27018` diff --git a/localbox/build_local_backend.sh b/localbox/build_local_backend.sh new file mode 100755 index 0000000..71a78b3 --- /dev/null +++ b/localbox/build_local_backend.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +load_local_env + +MAVEN_REPO_LOCAL="${MAVEN_REPO_LOCAL:-$ROOT_DIR/var/local-maven-repo}" +INSTALL_PRIVATE_SCRIPT="$SCRIPT_DIR/install_private_maven.py" + +usage() { + cat <<'EOF' +用法: + ./build_local_backend.sh # 构建全部 Java 后端 jar(需要 JDK 17) + ./build_local_backend.sh auth live # 只构建指定服务 +EOF +} + +all_java_services() { + cat <<'EOF' +auth +console +external +game-fruit +gateway +live +order +other +scheduling +visual-monitor +wallet +EOF +} + +module_for_service() { + case "$1" in + gateway) echo "rc-gateway" ;; + auth) echo "rc-auth" ;; + external) echo "rc-service/rc-service-external/external-start" ;; + other) echo "rc-service/rc-service-other/other-start" ;; + live) echo "rc-service/rc-service-live/live-start" ;; + order) echo "rc-service/rc-service-order/order-start" ;; + wallet) echo "rc-service/rc-service-wallet/wallet-start" ;; + console) echo "rc-service/rc-service-console/console-start" ;; + visual-monitor) echo "rc-visual/visual-monitor" ;; + scheduling) echo "rc-scheduling" ;; + game-fruit) echo "rc-service-game/game-fruit" ;; + *) + return 1 + ;; + esac +} + +select_services() { + if [ "$#" -eq 0 ]; then + all_java_services + return 0 + fi + + for service in "$@"; do + if ! module_for_service "$service" >/dev/null; then + echo "unknown java service: $service" >&2 + usage >&2 + exit 1 + fi + printf '%s\n' "$service" + done +} + +mkdir -p "$MAVEN_REPO_LOCAL" + +require_java_17 + +python3 "$INSTALL_PRIVATE_SCRIPT" \ + --source-root "$JAVA_REPO_DIR/maven_private" \ + --maven-repo-local "$MAVEN_REPO_LOCAL" + +SELECTED_SERVICES=() +while IFS= read -r service; do + [ -n "$service" ] || continue + SELECTED_SERVICES+=("$service") +done </dev/null | sed -n '1s/.*://p' +} + +probe_app_service() { + local service="$1" + local container_name container_state health_url + local probe_payload http_code body status detail + + container_name="$(container_name_for_service "$service")" + container_state="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_name" 2>/dev/null || printf 'missing')" + health_url="$(health_url_for_service "$service")" + + probe_payload="$(http_probe "$health_url")" + http_code="$(printf '%s\n' "$probe_payload" | sed -n '1p')" + body="$(printf '%s\n' "$probe_payload" | sed '1d')" + + status="FAIL" + detail="container=${container_state} http=${http_code}" + + if [ "$http_code" = "200" ]; then + if [ "$service" = "golang" ]; then + status="OK" + detail="container=${container_state} http=200 path=/health" + else + local actuator_status reason + actuator_status="$(printf '%s' "$body" | jq -r '.status // empty' 2>/dev/null || true)" + if [ "$actuator_status" = "UP" ]; then + status="OK" + detail="container=${container_state} actuator=UP" + else + reason="$(printf '%s' "$body" | jq -r '.components.refreshScope.details.error // .components.db.details.error // .error // empty' 2>/dev/null || true)" + detail="container=${container_state} actuator=${actuator_status:-unknown}" + if [ -n "$reason" ]; then + detail="$detail reason=$(printf '%s' "$reason" | tr '\n' ' ' | cut -c1-120)" + fi + fi + fi + else + local reason + reason="$(printf '%s' "$body" | jq -r '.errorMsg // .message // .status // empty' 2>/dev/null || true)" + if [ -n "$reason" ]; then + detail="$detail reason=$(printf '%s' "$reason" | tr '\n' ' ' | cut -c1-120)" + fi + fi + + if [ "$status" != "OK" ]; then + FAILURES=$((FAILURES + 1)) + fi + + print_row "$service" "$status" "$container_state" "$detail" +} + +probe_infra_service() { + local service="$1" + local container_name container_state status detail + + container_name="$(container_name_for_service "$service")" + container_state="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_name" 2>/dev/null || printf 'missing')" + status="FAIL" + detail="container=${container_state}" + + case "$service" in + nacos) + local probe_payload http_code body nacos_status + probe_payload="$(http_probe "http://127.0.0.1:${LIKEI_LOCAL_NACOS_PORT}/nacos/actuator/health")" + http_code="$(printf '%s\n' "$probe_payload" | sed -n '1p')" + body="$(printf '%s\n' "$probe_payload" | sed '1d')" + nacos_status="$(printf '%s' "$body" | jq -r '.status // empty' 2>/dev/null || true)" + if [ "$http_code" = "200" ] && [ "$nacos_status" = "UP" ]; then + status="OK" + detail="container=${container_state} actuator=UP" + else + detail="container=${container_state} http=${http_code} actuator=${nacos_status:-unknown}" + fi + ;; + zookeeper) + local zk_host_port + zk_host_port="$(published_host_port "$container_name" "2181/tcp")" + if [ -z "$zk_host_port" ]; then + zk_host_port="${LIKEI_LOCAL_ZOOKEEPER_EXPOSE_PORT}" + fi + if nc -z 127.0.0.1 "$zk_host_port" >/dev/null 2>&1; then + status="OK" + detail="container=${container_state} tcp=open port=${zk_host_port}" + else + detail="container=${container_state} tcp=not_ready port=${zk_host_port}" + fi + ;; + rocketmq-namesrv) + if nc -z 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" >/dev/null 2>&1; then + status="OK" + detail="container=${container_state} tcp=open port=${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" + else + detail="container=${container_state} tcp=not_ready port=${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" + fi + ;; + rocketmq-broker) + if docker exec chatapp3-local-rocketmq-broker sh mqadmin clusterList -n rocketmq-namesrv:9876 2>/dev/null | grep -q "DefaultCluster"; then + status="OK" + detail="container=${container_state} cluster=DefaultCluster" + else + detail="container=${container_state} cluster=not_ready" + fi + ;; + rocketmq-proxy) + if nc -z 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" >/dev/null 2>&1; then + status="OK" + detail="container=${container_state} tcp=open port=${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" + else + detail="container=${container_state} tcp=not_ready port=${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" + fi + ;; + *) + if [ "$container_state" = "healthy" ] || [ "$container_state" = "running" ]; then + status="OK" + detail="container=${container_state}" + fi + ;; + esac + + if [ "$status" != "OK" ]; then + FAILURES=$((FAILURES + 1)) + fi + + print_row "$service" "$status" "$container_state" "$detail" +} + +echo "App Services" +print_row "SERVICE" "RESULT" "CONTAINER" "DETAIL" +for service in "${APP_SERVICES[@]}"; do + probe_app_service "$service" +done + +echo +echo "Infra Services" +print_row "SERVICE" "RESULT" "CONTAINER" "DETAIL" +for service in "${INFRA_SERVICES[@]}"; do + probe_infra_service "$service" +done + +echo +if [ "$FAILURES" -eq 0 ]; then + echo "SUMMARY: all checked local backend services are healthy" +else + echo "SUMMARY: $FAILURES service(s) need attention" + exit 1 +fi diff --git a/localbox/common.sh b/localbox/common.sh new file mode 100644 index 0000000..4345178 --- /dev/null +++ b/localbox/common.sh @@ -0,0 +1,344 @@ +#!/usr/bin/env bash + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +COMPOSE_FILE="$ROOT_DIR/local-services.compose.yml" +ENV_FILE="${LIKEI_ENV_FILE:-$ROOT_DIR/.env.local}" +DOCKER_APP_BIN_DIR="/Applications/Docker.app/Contents/Resources/bin" + +resolve_default_workspace_dir() { + local candidate + for candidate in "$ROOT_DIR/.." "$ROOT_DIR/../chatapp3" "$ROOT_DIR/../../chatapp3" "$ROOT_DIR/../.."; do + if [ -d "$candidate/chatapp3-java" ] && [ -d "$candidate/chatapp3-golang" ]; then + cd "$candidate" && pwd + return 0 + fi + done + cd "$ROOT_DIR/.." && pwd +} + +DEFAULT_WORKSPACE_DIR="$(resolve_default_workspace_dir)" +WORKSPACE_DIR="$DEFAULT_WORKSPACE_DIR" +JAVA_REPO_DIR="$WORKSPACE_DIR/chatapp3-java" +GOLANG_REPO_DIR="$WORKSPACE_DIR/chatapp3-golang" + +configure_local_repo_paths() { + if [ -n "${LIKEI_WORKSPACE_DIR:-}" ]; then + WORKSPACE_DIR="$(cd "$LIKEI_WORKSPACE_DIR" && pwd)" + else + WORKSPACE_DIR="$DEFAULT_WORKSPACE_DIR" + fi + + JAVA_REPO_DIR="${LIKEI_LOCAL_JAVA_REPO_DIR:-$WORKSPACE_DIR/chatapp3-java}" + GOLANG_REPO_DIR="${LIKEI_LOCAL_GOLANG_REPO_DIR:-$WORKSPACE_DIR/chatapp3-golang}" + + export WORKSPACE_DIR + export JAVA_REPO_DIR + export GOLANG_REPO_DIR + export LIKEI_LOCAL_JAVA_REPO_DIR="$JAVA_REPO_DIR" + export LIKEI_LOCAL_GOLANG_REPO_DIR="$GOLANG_REPO_DIR" +} + +configure_local_repo_paths + +trim_spaces() { + local value="${1:-}" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + printf '%s' "$value" +} + +strip_wrapping_quotes() { + local value="${1:-}" + if [ "${#value}" -ge 2 ]; then + case "$value" in + \"*\") + printf '%s' "${value:1:${#value}-2}" + return 0 + ;; + \'*\') + printf '%s' "${value:1:${#value}-2}" + return 0 + ;; + esac + fi + printf '%s' "$value" +} + +is_truthy() { + case "${1:-}" in + 1|true|TRUE|True|yes|YES|Yes|y|Y|on|ON|On) + return 0 + ;; + *) + return 1 + ;; + esac +} + +local_rocketmq_disabled() { + is_truthy "${LIKEI_ROCKETMQ_LOCAL_DISABLE:-true}" +} + +configure_local_runtime_defaults() { + if [ -z "${LIKEI_LOCAL_OTHER_JAVA_OPTS_EXTRA+x}" ]; then + if local_rocketmq_disabled; then + export LIKEI_LOCAL_OTHER_JAVA_OPTS_EXTRA="-Dspring.autoconfigure.exclude=com.red.circle.component.mq.config.RocketMQAutoConfiguration" + else + export LIKEI_LOCAL_OTHER_JAVA_OPTS_EXTRA="" + fi + fi +} + +load_local_env() { + if [ -f "$ENV_FILE" ]; then + while IFS= read -r raw_line || [ -n "$raw_line" ]; do + local line key value + line="$(trim_spaces "$raw_line")" + [ -n "$line" ] || continue + case "$line" in + \#*) + continue + ;; + export\ *) + line="${line#export }" + ;; + esac + case "$line" in + *=*) + key="${line%%=*}" + value="${line#*=}" + key="$(trim_spaces "$key")" + value="$(trim_spaces "$value")" + value="$(strip_wrapping_quotes "$value")" + export "$key=$value" + ;; + esac + done < "$ENV_FILE" + fi + export LIKEI_ENV_FILE="$ENV_FILE" + export LIKEI_ENV_MODE="local" + configure_local_repo_paths + configure_local_runtime_defaults +} + +ensure_docker_cli() { + if command -v docker >/dev/null 2>&1; then + return 0 + fi + if [ -d "$DOCKER_APP_BIN_DIR" ]; then + export PATH="$DOCKER_APP_BIN_DIR:$PATH" + fi + command -v docker >/dev/null 2>&1 +} + +wait_for_docker() { + ensure_docker_cli || { + echo "docker CLI not found" >&2 + exit 1 + } + + if docker info >/dev/null 2>&1; then + return 0 + fi + + if [ -d "/Applications/Docker.app" ]; then + open -a Docker >/dev/null 2>&1 || true + fi + + for _ in $(seq 1 120); do + if docker info >/dev/null 2>&1; then + return 0 + fi + sleep 2 + done + + echo "docker daemon did not become ready in time" >&2 + exit 1 +} + +compose() { + docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" "$@" +} + +wait_http() { + local url="$1" + local retries="${2:-120}" + for _ in $(seq 1 "$retries"); do + if curl -fsS "$url" >/dev/null 2>&1; then + return 0 + fi + sleep 2 + done + echo "service did not become healthy in time: $url" >&2 + exit 1 +} + +wait_tcp_port() { + local host="$1" + local port="$2" + local retries="${3:-120}" + for _ in $(seq 1 "$retries"); do + if nc -z "$host" "$port" >/dev/null 2>&1; then + return 0 + fi + sleep 2 + done + echo "tcp port did not become ready in time: $host:$port" >&2 + exit 1 +} + +wait_container_healthy() { + local container_name="$1" + local retries="${2:-120}" + for _ in $(seq 1 "$retries"); do + local state + state="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_name" 2>/dev/null || true)" + if [ "$state" = "healthy" ] || [ "$state" = "running" ]; then + return 0 + fi + sleep 2 + done + echo "container did not become healthy in time: $container_name" >&2 + exit 1 +} + +wait_rocketmq_cluster() { + local retries="${1:-120}" + for _ in $(seq 1 "$retries"); do + if docker exec chatapp3-local-rocketmq-broker sh mqadmin clusterList -n rocketmq-namesrv:9876 2>/dev/null | grep -q "DefaultCluster"; then + return 0 + fi + sleep 2 + done + echo "rocketmq cluster did not become ready in time: DefaultCluster" >&2 + exit 1 +} + +wait_local_rocketmq() { + if local_rocketmq_disabled; then + return 0 + fi + + require_env LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT + require_env LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT + + wait_container_healthy chatapp3-local-rocketmq-namesrv 120 + wait_container_healthy chatapp3-local-rocketmq-broker 120 + wait_container_healthy chatapp3-local-rocketmq-proxy 120 + wait_tcp_port 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" 120 + wait_rocketmq_cluster 120 + wait_tcp_port 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" 120 +} + +require_env() { + local key="$1" + if [ -z "${!key:-}" ]; then + echo "required environment variable is missing: $key" >&2 + exit 1 + fi +} + +java_major_version() { + if ! command -v java >/dev/null 2>&1; then + return 1 + fi + + local raw_version major + raw_version="$(java -version 2>&1 | awk -F '"' '/version/ {print $2; exit}')" + [ -n "$raw_version" ] || return 1 + + major="${raw_version%%.*}" + if [ "$major" = "1" ]; then + major="$(printf '%s\n' "$raw_version" | awk -F. '{print $2}')" + fi + + printf '%s\n' "$major" +} + +require_java_17() { + local major + major="$(java_major_version || true)" + if [ -z "$major" ]; then + echo "java not found; rebuilding local Java services requires JDK 17" >&2 + exit 1 + fi + if [ "$major" != "17" ]; then + echo "rebuilding local Java services requires JDK 17; current java major version is $major" >&2 + exit 1 + fi +} + +is_java_service() { + case "$1" in + gateway|auth|external|other|live|order|wallet|console|visual-monitor|scheduling|game-fruit) + return 0 + ;; + *) + return 1 + ;; + esac +} + +java_artifact_path_for_service() { + case "$1" in + gateway) printf '%s\n' "$JAVA_REPO_DIR/rc-gateway/target/rc-gateway-1.0.0-local.jar" ;; + auth) printf '%s\n' "$JAVA_REPO_DIR/rc-auth/target/rc-auth-1.0.0-local.jar" ;; + external) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-external/external-start/target/rc-service-external-1.0.0-local.jar" ;; + other) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-other/other-start/target/rc-service-other-1.0.0-local.jar" ;; + live) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-live/live-start/target/rc-service-live-1.0.0-local.jar" ;; + order) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-order/order-start/target/rc-service-order-1.0.0-local.jar" ;; + wallet) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-wallet/wallet-start/target/rc-service-wallet-1.0.0-local.jar" ;; + console) printf '%s\n' "$JAVA_REPO_DIR/rc-service/rc-service-console/console-start/target/rc-service-console-1.0.0-local.jar" ;; + visual-monitor) printf '%s\n' "$JAVA_REPO_DIR/rc-visual/visual-monitor/target/visual-monitor-1.0.0-local.jar" ;; + scheduling) printf '%s\n' "$JAVA_REPO_DIR/rc-scheduling/target/rc-scheduling-1.0.0-local.jar" ;; + game-fruit) printf '%s\n' "$JAVA_REPO_DIR/rc-service-game/game-fruit/target/game-fruit-1.0.0-local.jar" ;; + *) + return 1 + ;; + esac +} + +all_local_java_jars_present() { + local service artifact_path + for service in gateway auth external other live order wallet console visual-monitor scheduling game-fruit; do + artifact_path="$(java_artifact_path_for_service "$service")" || return 1 + if [ ! -f "$artifact_path" ]; then + echo "missing local jar: $artifact_path" >&2 + return 1 + fi + done +} + +service_port() { + local env_key + case "$1" in + gateway) env_key="LIKEI_LOCAL_GATEWAY_PORT" ;; + auth) env_key="LIKEI_LOCAL_AUTH_PORT" ;; + wallet) env_key="LIKEI_LOCAL_WALLET_PORT" ;; + other) env_key="LIKEI_LOCAL_OTHER_PORT" ;; + live) env_key="LIKEI_LOCAL_LIVE_PORT" ;; + order) env_key="LIKEI_LOCAL_ORDER_PORT" ;; + console) env_key="LIKEI_LOCAL_CONSOLE_PORT" ;; + scheduling) env_key="LIKEI_LOCAL_SCHEDULING_PORT" ;; + golang) env_key="LIKEI_LOCAL_GOLANG_PORT" ;; + external) env_key="LIKEI_LOCAL_EXTERNAL_PORT" ;; + visual-monitor) env_key="LIKEI_LOCAL_VISUAL_MONITOR_PORT" ;; + game-fruit) env_key="LIKEI_LOCAL_GAME_FRUIT_PORT" ;; + *) + return 1 + ;; + esac + require_env "$env_key" + printf '%s\n' "${!env_key}" +} + +wait_service_port() { + local service="$1" + local retries="${2:-120}" + local port + port="$(service_port "$service")" || { + echo "unknown app service port: $service" >&2 + exit 1 + } + wait_tcp_port 127.0.0.1 "$port" "$retries" +} diff --git a/localbox/create_local_app_user.sh b/localbox/create_local_app_user.sh new file mode 100755 index 0000000..b8cda23 --- /dev/null +++ b/localbox/create_local_app_user.sh @@ -0,0 +1,326 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ===== 修改这里即可 ===== +ACCOUNT="${ACCOUNT:-1234567}" +PASSWORD="${PASSWORD:-$ACCOUNT}" +GATEWAY_BASE_URL="${GATEWAY_BASE_URL:-http://192.168.110.64:1100}" + +SYS_ORIGIN="${SYS_ORIGIN:-LIKEI}" +SYS_ORIGIN_CHILD="${SYS_ORIGIN_CHILD:-LIKEI}" +NICKNAME="${NICKNAME:-local-${ACCOUNT}}" +PHONE_PREFIX="${PHONE_PREFIX:-86}" +PHONE_NUMBER="${PHONE_NUMBER:-138$(date +%d%H%M%S)}" +OPEN_ID="${OPEN_ID:-local-${ACCOUNT}-${PHONE_NUMBER}}" +COUNTRY_CODE="${COUNTRY_CODE:-CN}" +COUNTRY_NAME="${COUNTRY_NAME:-China}" +COUNTRY_ID="${COUNTRY_ID:-}" + +MYSQL_CONTAINER="${MYSQL_CONTAINER:-chatapp3-local-mysql}" +MYSQL_DATABASE="${MYSQL_DATABASE:-likei}" +MYSQL_USER="${MYSQL_USER:-root}" +MYSQL_PASSWORD="${MYSQL_PASSWORD:-123456}" +REDIS_CONTAINER="${REDIS_CONTAINER:-chatapp3-local-redis}" + +REQ_CLIENT="${REQ_CLIENT:-Android}" +REQ_APP_INTEL="${REQ_APP_INTEL:-version=1.0.0;build=1;model=LocalScript;sysVersion=Mac;channel=local;}" +REQ_LANG="${REQ_LANG:-zh-CN}" +REQ_ZONE="${REQ_ZONE:-Asia/Shanghai}" +REQ_IMEI="${REQ_IMEI:-local-create-app-user-${ACCOUNT}}" +HTTP_TIMEOUT="${HTTP_TIMEOUT:-15}" +# ======================== + +GATEWAY_BASE_URL="${GATEWAY_BASE_URL%/}" + +log() { + printf '[create-local-app-user] %s\n' "$*" +} + +die() { + printf '[create-local-app-user] ERROR: %s\n' "$*" >&2 + exit 1 +} + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || die "缺少命令: $1" +} + +sql_quote() { + printf "%s" "$1" | sed "s/'/''/g" +} + +mysql_exec() { + docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$MYSQL_CONTAINER" \ + mysql -u"$MYSQL_USER" "$MYSQL_DATABASE" +} + +mysql_scalar() { + docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$MYSQL_CONTAINER" \ + mysql -u"$MYSQL_USER" -N -B "$MYSQL_DATABASE" -e "$1" | head -n 1 +} + +json_login_payload() { + ACCOUNT="$ACCOUNT" PASSWORD="$PASSWORD" python3 - <<'PY' +import json +import os + +print(json.dumps({ + "account": os.environ["ACCOUNT"], + "pwd": os.environ["PASSWORD"], +}, ensure_ascii=False)) +PY +} + +json_register_payload() { + ACCOUNT="$ACCOUNT" PASSWORD="$PASSWORD" NICKNAME="$NICKNAME" OPEN_ID="$OPEN_ID" \ + PHONE_PREFIX="$PHONE_PREFIX" PHONE_NUMBER="$PHONE_NUMBER" \ + COUNTRY_CODE="$COUNTRY_CODE" COUNTRY_NAME="$COUNTRY_NAME" COUNTRY_ID="$COUNTRY_ID" \ + python3 - <<'PY' +import json +import os + +profile = { + "userNickname": os.environ["NICKNAME"], + "userAvatar": "", + "userSex": 1, + "bornYear": 1998, + "bornMonth": 1, + "bornDay": 1, +} + +if os.environ.get("COUNTRY_CODE"): + profile["countryCode"] = os.environ["COUNTRY_CODE"] +if os.environ.get("COUNTRY_NAME"): + profile["countryName"] = os.environ["COUNTRY_NAME"] +if os.environ.get("COUNTRY_ID"): + profile["countryId"] = int(os.environ["COUNTRY_ID"]) + +print(json.dumps({ + "type": "MOBILE", + "openId": os.environ["OPEN_ID"], + "profile": profile, + "mobile": { + "phonePrefix": int(os.environ["PHONE_PREFIX"]), + "phoneNumber": os.environ["PHONE_NUMBER"], + "pwd": os.environ["PASSWORD"], + "code": "000000", + }, +}, ensure_ascii=False)) +PY +} + +api_post() { + local path="$1" + local body="$2" + local output="$3" + local code + + code="$(curl -sS -m "$HTTP_TIMEOUT" -o "$output" -w "%{http_code}" \ + -X POST "${GATEWAY_BASE_URL}${path}" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H "Req-Sys-Origin: origin=${SYS_ORIGIN};originChild=${SYS_ORIGIN_CHILD}" \ + -H "Req-Client: ${REQ_CLIENT}" \ + -H "Req-App-Intel: ${REQ_APP_INTEL}" \ + -H "Req-Lang: ${REQ_LANG}" \ + -H "Req-Zone: ${REQ_ZONE}" \ + -H "req-imei: ${REQ_IMEI}" \ + --data "$body" || true)" + + [[ "$code" == 2* ]] +} + +json_status_ok() { + python3 - "$1" <<'PY' +import json +import sys + +try: + data = json.load(open(sys.argv[1], encoding="utf-8")) +except Exception: + sys.exit(1) + +if isinstance(data, dict) and "status" in data: + sys.exit(0 if data.get("status") is True else 1) + +sys.exit(0) +PY +} + +print_api_error() { + python3 - "$1" <<'PY' +import json +import sys + +text = open(sys.argv[1], encoding="utf-8").read() +try: + data = json.loads(text) +except Exception: + print(text) + sys.exit(0) + +if isinstance(data, dict): + msg = data.get("errorMsg") or data.get("message") or data + print(msg) +else: + print(data) +PY +} + +extract_user_id() { + python3 - "$1" <<'PY' +import json +import sys + +data = json.load(open(sys.argv[1], encoding="utf-8")) +body = data.get("body", data) if isinstance(data, dict) else {} +profile = body.get("userProfile", {}) if isinstance(body, dict) else {} +user_id = profile.get("id") or profile.get("userId") or body.get("userId") +print(user_id or "") +PY +} + +extract_account() { + python3 - "$1" <<'PY' +import json +import sys + +data = json.load(open(sys.argv[1], encoding="utf-8")) +body = data.get("body", data) if isinstance(data, dict) else {} +profile = body.get("userProfile", {}) if isinstance(body, dict) else {} +print(profile.get("account") or "") +PY +} + +try_login() { + local output="$1" + local payload + payload="$(json_login_payload)" + api_post "/auth/account/login" "$payload" "$output" && json_status_ok "$output" +} + +generate_password_hash() { + local raw + raw="$(htpasswd -bnBC 10 '' "$PASSWORD" | sed 's/^://')" + printf '{bcrypt}%s' "$raw" +} + +ensure_account_password() { + local user_id="$1" + local password_hash="$2" + local account_q origin_q origin_child_q hash_q + + account_q="$(sql_quote "$ACCOUNT")" + origin_q="$(sql_quote "$SYS_ORIGIN")" + origin_child_q="$(sql_quote "$SYS_ORIGIN_CHILD")" + hash_q="$(sql_quote "$password_hash")" + + mysql_exec </dev/null; done + redis-cli DEL 'USER:HASH:${user_id}' 'USER:PROFILE:${user_id}' 'USER:USER_RUN_PROFILE:${user_id}' 'USER:USER_REGION:${user_id}' >/dev/null + " >/dev/null || true + fi +} + +main() { + require_cmd curl + require_cmd docker + require_cmd python3 + require_cmd htpasswd + + docker ps --format '{{.Names}}' | grep -qx "$MYSQL_CONTAINER" \ + || die "MySQL 容器未运行: ${MYSQL_CONTAINER}" + + log "目标账号: ${ACCOUNT}" + log "网关地址: ${GATEWAY_BASE_URL}" + + local login_response + login_response="$(mktemp)" + if try_login "$login_response"; then + log "账号已可登录,无需创建。userId=$(extract_user_id "$login_response") account=$(extract_account "$login_response")" + rm -f "$login_response" + return + fi + + local login_error + login_error="$(print_api_error "$login_response")" + rm -f "$login_response" + + if [[ -z "$login_error" || "$login_error" == *"Connection refused"* || "$login_error" == *"timed out"* || "$login_error" == *"No route"* ]]; then + die "登录接口不可用,请先检查 GATEWAY_BASE_URL/auth/other 服务。原因: ${login_error:-empty response}" + fi + + log "直接登录未通过,开始创建或补齐本地账号密码。原因: ${login_error}" + + local account_q origin_q existing_user_id user_id + account_q="$(sql_quote "$ACCOUNT")" + origin_q="$(sql_quote "$SYS_ORIGIN")" + existing_user_id="$(mysql_scalar "SELECT id FROM user_base_info WHERE account='${account_q}' AND origin_sys='${origin_q}' AND is_del=0 LIMIT 1;")" + + if [[ -n "$existing_user_id" ]]; then + user_id="$existing_user_id" + log "账号已存在,重置账号密码登录信息。userId=${user_id}" + else + local create_response create_payload generated_account + create_response="$(mktemp)" + create_payload="$(json_register_payload)" + + log "账号不存在,先走 App 注册接口创建完整用户。phone=+${PHONE_PREFIX} ${PHONE_NUMBER}" + api_post "/auth/account/create" "$create_payload" "$create_response" \ + || die "注册接口请求失败: $(print_api_error "$create_response")" + json_status_ok "$create_response" \ + || die "注册接口返回失败: $(print_api_error "$create_response")" + + user_id="$(extract_user_id "$create_response")" + generated_account="$(extract_account "$create_response")" + rm -f "$create_response" + + [[ -n "$user_id" ]] || die "注册成功但未解析到 userId" + log "注册成功,userId=${user_id} generatedAccount=${generated_account},开始绑定指定账号 ${ACCOUNT}" + fi + + ensure_account_password "$user_id" "$(generate_password_hash)" + clear_login_cache "$user_id" + + local verify_response + verify_response="$(mktemp)" + if try_login "$verify_response"; then + log "验证登录成功。userId=$(extract_user_id "$verify_response") account=$(extract_account "$verify_response") password=${PASSWORD}" + rm -f "$verify_response" + return + fi + + die "账号已写入,但登录验证失败: $(print_api_error "$verify_response")" +} + +main "$@" diff --git a/localbox/deploy.sh b/localbox/deploy.sh new file mode 100755 index 0000000..cdd081a --- /dev/null +++ b/localbox/deploy.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +LOCAL_DIR="$ROOT_DIR" + +usage() { + cat <<'EOF' +用法: + ./deploy.sh start [--skip-build] [--infra-only] + ./deploy.sh build [service...] + ./deploy.sh restart [--rebuild] + ./deploy.sh check + ./deploy.sh publish-nacos + +说明: + 当前仓库只保留本地部署和本地联调能力。 + 如果第一个参数是 `--skip-build` 或 `--infra-only`,会默认转给 `start`。 +EOF +} + +run_local_script() { + local script_name="$1" + shift + exec "$LOCAL_DIR/$script_name" "$@" +} + +if [ "$#" -eq 0 ]; then + usage + exit 0 +fi + +case "$1" in + --skip-build|--infra-only) + run_local_script start_local_services.sh "$@" + ;; + start) + shift + run_local_script start_local_services.sh "$@" + ;; + build) + shift + run_local_script build_local_backend.sh "$@" + ;; + restart) + shift + run_local_script restart_local_service.sh "$@" + ;; + check) + shift + run_local_script check_local_services.sh "$@" + ;; + publish-nacos) + shift + run_local_script publish_local_nacos_configs.sh "$@" + ;; + -h|--help|help) + usage + ;; + *) + echo "unknown command: $1" >&2 + usage >&2 + exit 1 + ;; +esac diff --git a/localbox/install_private_maven.py b/localbox/install_private_maven.py new file mode 100644 index 0000000..363f563 --- /dev/null +++ b/localbox/install_private_maven.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import subprocess +from pathlib import Path + + +def run(command: list[str], cwd: Path | None = None) -> None: + subprocess.run(command, cwd=cwd, check=True) + + +def install_private_artifacts(maven_private_root: Path, maven_repo_local: str) -> int: + if not maven_private_root.exists(): + raise SystemExit(f"missing private maven directory: {maven_private_root}") + + install_count = 0 + for version_dir in sorted(path for path in maven_private_root.glob("*/*") if path.is_dir()): + pom_candidates = sorted(version_dir.glob("*.pom")) + jar_candidates = sorted( + path + for path in version_dir.glob("*.jar") + if path.is_file() and not path.name.startswith("original-") + ) + if not pom_candidates: + continue + + pom_file = pom_candidates[0] + command = [ + "mvn", + f"-Dmaven.repo.local={maven_repo_local}", + "install:install-file", + f"-DpomFile={pom_file}", + "-DgeneratePom=false", + ] + + if jar_candidates: + jar_file = jar_candidates[0] + print(f"install private maven artifact: {jar_file.name}", flush=True) + command.append(f"-Dfile={jar_file}") + else: + print(f"install private maven pom: {pom_file.name}", flush=True) + command.extend( + [ + f"-Dfile={pom_file}", + "-Dpackaging=pom", + ] + ) + + run(command) + install_count += 1 + return install_count + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--source-root", type=Path, required=True) + parser.add_argument("--maven-repo-local", required=True) + args = parser.parse_args() + installed = install_private_artifacts(args.source_root, args.maven_repo_local) + print(f"installed private artifacts: {installed}", flush=True) + + +if __name__ == "__main__": + main() diff --git a/localbox/local-infra.compose.yml b/localbox/local-infra.compose.yml new file mode 100644 index 0000000..43a37ca --- /dev/null +++ b/localbox/local-infra.compose.yml @@ -0,0 +1,49 @@ +name: chatapp3-local-infra + +services: + mysql: + env_file: + - ./.env.local + image: docker.m.daocloud.io/library/mysql:8.4 + container_name: likei-local-mysql + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${LIKEI_LOCAL_MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${LIKEI_LOCAL_MYSQL_DATABASE} + TZ: ${TZ} + ports: + - "${LIKEI_LOCAL_MYSQL_INFRA_EXPOSE_PORT}:3306" + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --default-time-zone=+08:00 + - --mysql-native-password=ON + volumes: + - likei-local-mysql-data:/var/lib/mysql + - ./local-infra/mysql/init:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -uroot -p${LIKEI_LOCAL_MYSQL_ROOT_PASSWORD} --silent"] + interval: 5s + timeout: 5s + retries: 30 + + redis: + env_file: + - ./.env.local + image: docker.m.daocloud.io/library/redis:7-alpine + container_name: likei-local-redis + restart: unless-stopped + ports: + - "${LIKEI_LOCAL_REDIS_INFRA_EXPOSE_PORT}:6379" + command: ["redis-server", "--appendonly", "yes"] + volumes: + - likei-local-redis-data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 30 + +volumes: + likei-local-mysql-data: + likei-local-redis-data: diff --git a/localbox/local-infra/mysql/init/001_chatapp3_base.sql b/localbox/local-infra/mysql/init/001_chatapp3_base.sql new file mode 100644 index 0000000..a561619 --- /dev/null +++ b/localbox/local-infra/mysql/init/001_chatapp3_base.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS user_base_info ( + id BIGINT NOT NULL PRIMARY KEY, + account VARCHAR(64) DEFAULT NULL, + user_avatar VARCHAR(255) DEFAULT NULL, + user_nickname VARCHAR(255) DEFAULT NULL, + origin_sys VARCHAR(32) DEFAULT NULL, + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS invite_code_mapping ( + user_id BIGINT NOT NULL PRIMARY KEY, + invite_code VARCHAR(32) NOT NULL, + account VARCHAR(64) DEFAULT NULL, + UNIQUE KEY uk_invite_code (invite_code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/localbox/local-infra/rocketmq/broker.conf b/localbox/local-infra/rocketmq/broker.conf new file mode 100644 index 0000000..c37367c --- /dev/null +++ b/localbox/local-infra/rocketmq/broker.conf @@ -0,0 +1,8 @@ +brokerClusterName=DefaultCluster +brokerName=broker-a +brokerId=0 +deleteWhen=04 +fileReservedTime=48 +brokerRole=ASYNC_MASTER +flushDiskType=ASYNC_FLUSH +autoCreateTopicEnable=true diff --git a/localbox/local-infra/rocketmq/start-proxy.sh b/localbox/local-infra/rocketmq/start-proxy.sh new file mode 100644 index 0000000..d6ab2ff --- /dev/null +++ b/localbox/local-infra/rocketmq/start-proxy.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env sh +set -eu + +NAMESRV_ADDR="${NAMESRV_ADDR:-rocketmq-namesrv:9876}" +ROCKETMQ_CLUSTER_NAME="${ROCKETMQ_CLUSTER_NAME:-DefaultCluster}" +ROCKETMQ_BOOTSTRAP_TOPICS="${ROCKETMQ_BOOTSTRAP_TOPICS:-DefaultHeartBeatSyncerTopic}" + +echo "waiting for RocketMQ cluster ${ROCKETMQ_CLUSTER_NAME} via ${NAMESRV_ADDR}" +i=0 +while [ "$i" -lt 60 ]; do + if sh mqadmin clusterList -n "$NAMESRV_ADDR" >/tmp/rocketmq-cluster.txt 2>/tmp/rocketmq-cluster.err; then + if grep -q "$ROCKETMQ_CLUSTER_NAME" /tmp/rocketmq-cluster.txt; then + break + fi + fi + i=$((i + 1)) + sleep 2 +done + +if [ "$i" -ge 60 ]; then + echo "rocketmq cluster did not become ready: ${ROCKETMQ_CLUSTER_NAME}" >&2 + cat /tmp/rocketmq-cluster.err >&2 || true + exit 1 +fi + +old_ifs="$IFS" +IFS=',' +set -- $ROCKETMQ_BOOTSTRAP_TOPICS +IFS="$old_ifs" + +for topic in "$@"; do + echo "ensuring RocketMQ topic ${topic}" + i=0 + while [ "$i" -lt 20 ]; do + if sh mqadmin updateTopic -n "$NAMESRV_ADDR" -c "$ROCKETMQ_CLUSTER_NAME" -t "$topic"; then + break + fi + i=$((i + 1)) + sleep 2 + done + + if [ "$i" -ge 20 ]; then + echo "failed to initialize RocketMQ topic: ${topic}" >&2 + exit 1 + fi +done + +exec sh mqproxy -n "$NAMESRV_ADDR" diff --git a/localbox/local-services.compose.yml b/localbox/local-services.compose.yml new file mode 100644 index 0000000..1435181 --- /dev/null +++ b/localbox/local-services.compose.yml @@ -0,0 +1,372 @@ +name: chatapp3-local + +x-env-file: &env-file + env_file: + - ./.env.local + +x-java-environment: &java-environment + JAVA_OPTS: ${LIKEI_LOCAL_JAVA_OPTS:--Xms128m -Xmx512m} + FEIGN_GATEWAY_URL: http://gateway:1100 + FEIGN_AUTH_URL: http://auth:1000 + FEIGN_WALLET_URL: http://wallet:2000 + FEIGN_OTHER_URL: http://other:2400 + FEIGN_LIVE_URL: http://live:2500 + FEIGN_ORDER_URL: http://order:2600 + FEIGN_CONSOLE_URL: http://console:2700 + FEIGN_EXTERNAL_URL: http://external:3000 + +x-java-service: &java-service + <<: *env-file + image: eclipse-temurin:17-jre + restart: unless-stopped + working_dir: /app + environment: + <<: *java-environment + command: + - sh + - -c + - java $$JAVA_OPTS -jar /app/app.jar + networks: + - localnet + +services: + mysql: + <<: *env-file + image: mysql:8.4 + container_name: chatapp3-local-mysql + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${LIKEI_LOCAL_MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${LIKEI_LOCAL_MYSQL_DATABASE} + TZ: ${TZ} + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --default-time-zone=+08:00 + - --mysql-native-password=ON + ports: + - "${LIKEI_LOCAL_MYSQL_EXPOSE_PORT}:3306" + volumes: + - chatapp3-local-mysql-data:/var/lib/mysql + - ./local-infra/mysql/init:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -uroot -p${LIKEI_LOCAL_MYSQL_ROOT_PASSWORD} --silent"] + interval: 5s + timeout: 5s + retries: 30 + networks: + - localnet + + redis: + <<: *env-file + image: redis:7-alpine + container_name: chatapp3-local-redis + restart: unless-stopped + command: ["redis-server", "--appendonly", "yes"] + ports: + - "${LIKEI_LOCAL_REDIS_EXPOSE_PORT}:6379" + volumes: + - chatapp3-local-redis-data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 30 + networks: + - localnet + + mongo: + <<: *env-file + image: mongo:7.0 + container_name: chatapp3-local-mongo + restart: unless-stopped + environment: + MONGO_INITDB_ROOT_USERNAME: ${LIKEI_LOCAL_MONGO_ROOT_USERNAME} + MONGO_INITDB_ROOT_PASSWORD: ${LIKEI_LOCAL_MONGO_ROOT_PASSWORD} + TZ: ${TZ} + ports: + - "${LIKEI_LOCAL_MONGO_EXPOSE_PORT}:27017" + volumes: + - chatapp3-local-mongo-data:/data/db + healthcheck: + test: + [ + "CMD-SHELL", + "mongosh --quiet mongodb://${LIKEI_LOCAL_MONGO_ROOT_USERNAME}:${LIKEI_LOCAL_MONGO_ROOT_PASSWORD}@127.0.0.1:27017/admin --eval 'db.runCommand({ ping: 1 }).ok' | grep -q 1", + ] + interval: 5s + timeout: 5s + retries: 30 + networks: + - localnet + + nacos: + <<: *env-file + image: nacos/nacos-server:v2.4.0 + container_name: chatapp3-local-nacos + restart: unless-stopped + environment: + MODE: standalone + PREFER_HOST_MODE: hostname + TZ: ${TZ} + NACOS_AUTH_ENABLE: ${LIKEI_LOCAL_NACOS_AUTH_ENABLE} + JVM_XMS: ${LIKEI_LOCAL_NACOS_JVM_XMS} + JVM_XMX: ${LIKEI_LOCAL_NACOS_JVM_XMX} + JVM_XMN: ${LIKEI_LOCAL_NACOS_JVM_XMN} + ports: + - "${LIKEI_LOCAL_NACOS_PORT}:8848" + - "${LIKEI_LOCAL_NACOS_CONSOLE_PORT}:8080" + - "${LIKEI_LOCAL_NACOS_CLIENT_GRPC_PORT}:9848" + networks: + - localnet + + zookeeper: + <<: *env-file + image: zookeeper:3.9 + container_name: chatapp3-local-zookeeper + restart: unless-stopped + environment: + TZ: ${TZ} + ports: + - "${LIKEI_LOCAL_ZOOKEEPER_EXPOSE_PORT}:2181" + networks: + - localnet + + rocketmq-namesrv: + <<: *env-file + image: apache/rocketmq:${LIKEI_LOCAL_ROCKETMQ_IMAGE_TAG:-5.3.2} + container_name: chatapp3-local-rocketmq-namesrv + restart: unless-stopped + command: ["sh", "mqnamesrv"] + environment: + TZ: ${TZ} + JAVA_OPT_EXT: ${LIKEI_LOCAL_ROCKETMQ_NAMESRV_JAVA_OPTS:--Xms128m -Xmx128m -Xmn64m} + ports: + - "${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}:9876" + networks: + - localnet + + rocketmq-init: + <<: *env-file + image: apache/rocketmq:${LIKEI_LOCAL_ROCKETMQ_IMAGE_TAG:-5.3.2} + container_name: chatapp3-local-rocketmq-init + restart: "no" + user: root + command: + - sh + - -c + - mkdir -p /home/rocketmq/store && chown -R rocketmq:root /home/rocketmq/store + volumes: + - chatapp3-local-rocketmq-store:/home/rocketmq/store + networks: + - localnet + + rocketmq-broker: + <<: *env-file + image: apache/rocketmq:${LIKEI_LOCAL_ROCKETMQ_IMAGE_TAG:-5.3.2} + container_name: chatapp3-local-rocketmq-broker + restart: unless-stopped + depends_on: + rocketmq-namesrv: + condition: service_started + rocketmq-init: + condition: service_completed_successfully + command: ["sh", "mqbroker", "-n", "rocketmq-namesrv:9876", "-c", "/home/rocketmq/rocketmq-5.3.2/conf/broker.conf"] + environment: + TZ: ${TZ} + NAMESRV_ADDR: rocketmq-namesrv:9876 + JAVA_OPT_EXT: ${LIKEI_LOCAL_ROCKETMQ_BROKER_JAVA_OPTS:--Xms256m -Xmx256m -Xmn128m} + volumes: + - ./local-infra/rocketmq/broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf:ro + - chatapp3-local-rocketmq-store:/home/rocketmq/store + networks: + - localnet + + rocketmq-proxy: + <<: *env-file + image: apache/rocketmq:${LIKEI_LOCAL_ROCKETMQ_IMAGE_TAG:-5.3.2} + container_name: chatapp3-local-rocketmq-proxy + restart: unless-stopped + depends_on: + - rocketmq-namesrv + - rocketmq-broker + command: ["/bin/sh", "/opt/rocketmq-ext/start-proxy.sh"] + environment: + TZ: ${TZ} + NAMESRV_ADDR: rocketmq-namesrv:9876 + ROCKETMQ_CLUSTER_NAME: DefaultCluster + ROCKETMQ_BOOTSTRAP_TOPICS: DefaultHeartBeatSyncerTopic,RC_DEFAULT_APP_ORDER,RC_DEFAULT_APP_ORDINARY,RC_DEFAULT_APP_DELAYED + JAVA_OPT_EXT: ${LIKEI_LOCAL_ROCKETMQ_PROXY_JAVA_OPTS:--Xms128m -Xmx256m -Xmn64m} + ports: + - "${LIKEI_LOCAL_ROCKETMQ_PROXY_HTTP_PORT}:8080" + - "${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}:8081" + volumes: + - ./local-infra/rocketmq/start-proxy.sh:/opt/rocketmq-ext/start-proxy.sh:ro + networks: + - localnet + + gateway: + <<: *java-service + container_name: chatapp3-local-gateway + depends_on: + - nacos + environment: + <<: *java-environment + FEIGN_AUTH_URL: http://rc-auth + ports: + - "${LIKEI_LOCAL_GATEWAY_PORT}:1100" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-gateway/target/rc-gateway-1.0.0-local.jar:/app/app.jar:ro + + auth: + <<: *java-service + container_name: chatapp3-local-auth + depends_on: + - nacos + ports: + - "${LIKEI_LOCAL_AUTH_PORT}:1000" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-auth/target/rc-auth-1.0.0-local.jar:/app/app.jar:ro + + external: + <<: *java-service + container_name: chatapp3-local-external + depends_on: + - nacos + ports: + - "${LIKEI_LOCAL_EXTERNAL_PORT}:3000" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-external/external-start/target/rc-service-external-1.0.0-local.jar:/app/app.jar:ro + + other: + <<: *java-service + container_name: chatapp3-local-other + depends_on: + - nacos + - mongo + environment: + <<: *java-environment + JAVA_OPTS: "${LIKEI_LOCAL_OTHER_JAVA_OPTS:--Xms128m -Xmx512m} ${LIKEI_LOCAL_OTHER_JAVA_OPTS_EXTRA:-}" + ports: + - "${LIKEI_LOCAL_OTHER_PORT}:2400" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-other/other-start/target/rc-service-other-1.0.0-local.jar:/app/app.jar:ro + + live: + <<: *java-service + container_name: chatapp3-local-live + depends_on: + - nacos + - mongo + ports: + - "${LIKEI_LOCAL_LIVE_PORT}:2500" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-live/live-start/target/rc-service-live-1.0.0-local.jar:/app/app.jar:ro + + order: + <<: *java-service + container_name: chatapp3-local-order + depends_on: + - nacos + - mongo + ports: + - "${LIKEI_LOCAL_ORDER_PORT}:2600" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-order/order-start/target/rc-service-order-1.0.0-local.jar:/app/app.jar:ro + + wallet: + <<: *java-service + container_name: chatapp3-local-wallet + depends_on: + - nacos + - mongo + ports: + - "${LIKEI_LOCAL_WALLET_PORT}:2000" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-wallet/wallet-start/target/rc-service-wallet-1.0.0-local.jar:/app/app.jar:ro + + console: + <<: *java-service + container_name: chatapp3-local-console + depends_on: + - nacos + - mongo + ports: + - "${LIKEI_LOCAL_CONSOLE_PORT}:2700" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service/rc-service-console/console-start/target/rc-service-console-1.0.0-local.jar:/app/app.jar:ro + + visual-monitor: + <<: *java-service + container_name: chatapp3-local-visual-monitor + depends_on: + - nacos + ports: + - "${LIKEI_LOCAL_VISUAL_MONITOR_PORT}:8000" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-visual/visual-monitor/target/visual-monitor-1.0.0-local.jar:/app/app.jar:ro + + scheduling: + <<: *java-service + container_name: chatapp3-local-scheduling + depends_on: + - nacos + - zookeeper + environment: + <<: *java-environment + JAVA_OPTS: ${LIKEI_LOCAL_SCHEDULING_JAVA_OPTS:--Xms128m -Xmx384m} + ports: + - "${LIKEI_LOCAL_SCHEDULING_PORT}:2800" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-scheduling/target/rc-scheduling-1.0.0-local.jar:/app/app.jar:ro + + game-fruit: + <<: *java-service + container_name: chatapp3-local-game-fruit + depends_on: + - nacos + environment: + <<: *java-environment + JAVA_OPTS: ${LIKEI_LOCAL_GAME_FRUIT_JAVA_OPTS:--Xms128m -Xmx384m} + SERVER_PORT: ${LIKEI_LOCAL_GAME_FRUIT_PORT} + ports: + - "${LIKEI_LOCAL_GAME_FRUIT_PORT}:8001" + volumes: + - ${LIKEI_LOCAL_JAVA_REPO_DIR:-../../chatapp3/chatapp3-java}/rc-service-game/game-fruit/target/game-fruit-1.0.0-local.jar:/app/app.jar:ro + + golang: + <<: *env-file + image: golang:1.24 + container_name: chatapp3-local-golang + restart: unless-stopped + depends_on: + - auth + - other + - wallet + - mysql + - redis + working_dir: /workspace/chatapp3-golang + command: + - sh + - -c + - go mod download && go run ./cmd/api + ports: + - "${LIKEI_LOCAL_GOLANG_PORT}:2900" + volumes: + - ${LIKEI_LOCAL_GOLANG_REPO_DIR:-../../chatapp3/chatapp3-golang}:/workspace/chatapp3-golang + - chatapp3-local-go-pkg:/go/pkg/mod + - chatapp3-local-go-build:/root/.cache/go-build + networks: + - localnet + +volumes: + chatapp3-local-go-build: + chatapp3-local-go-pkg: + chatapp3-local-mysql-data: + chatapp3-local-redis-data: + chatapp3-local-mongo-data: + chatapp3-local-rocketmq-store: + +networks: + localnet: + name: chatapp3-localnet diff --git a/localbox/publish_local_nacos_configs.sh b/localbox/publish_local_nacos_configs.sh new file mode 100755 index 0000000..f7e2782 --- /dev/null +++ b/localbox/publish_local_nacos_configs.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +load_local_env + +NACOS_SOURCE_DIR="${LIKEI_NACOS_CONFIG_ROOT:-$JAVA_REPO_DIR/nacos_config}" +NACOS_CONFIG_HOST="${NACOS_CONFIG_HOST:?missing NACOS_CONFIG_HOST}" +NACOS_CONFIG_PORT="${NACOS_CONFIG_PORT:?missing NACOS_CONFIG_PORT}" +NAMESPACE_ID="${NAMESPACE_ID:-${LIKEI_NACOS_NAMESPACE:?missing LIKEI_NACOS_NAMESPACE}}" +NAMESPACE_NAME="${NAMESPACE_NAME:-${LIKEI_NACOS_NAMESPACE_NAME:?missing LIKEI_NACOS_NAMESPACE_NAME}}" +NACOS_CONFIG_BASE_URL="http://${NACOS_CONFIG_HOST}:${NACOS_CONFIG_PORT}/nacos" + +TMP_DIR="$(mktemp -d)" +cleanup() { + rm -rf "$TMP_DIR" +} +trap cleanup EXIT + +cp -R "$NACOS_SOURCE_DIR/." "$TMP_DIR/" +if [ -f "$TMP_DIR/common/external.yml" ]; then + cp "$TMP_DIR/common/external.yml" "$TMP_DIR/common/external-config.yml" +fi + +if [ "$NAMESPACE_ID" != "public" ]; then + for _ in $(seq 1 60); do + if curl -fsS "${NACOS_CONFIG_BASE_URL}/" >/dev/null; then + break + fi + sleep 1 + done + + curl -fsS -X POST "$NACOS_CONFIG_BASE_URL/v1/console/namespaces" \ + --data-urlencode "customNamespaceId=${NAMESPACE_ID}" \ + --data-urlencode "namespaceName=${NAMESPACE_NAME}" \ + --data-urlencode "namespaceDesc=${NAMESPACE_NAME}" >/dev/null || true +fi + +publish_file() { + local file_path="$1" + local group="$2" + local data_id="$3" + + if [ "$NAMESPACE_ID" = "public" ]; then + curl -fsS -X POST "$NACOS_CONFIG_BASE_URL/v1/cs/configs" \ + --data-urlencode "group=${group}" \ + --data-urlencode "dataId=${data_id}" \ + --data-urlencode "type=yaml" \ + --data-urlencode "content@${file_path}" >/dev/null + else + curl -fsS -X POST "$NACOS_CONFIG_BASE_URL/v1/cs/configs" \ + --data-urlencode "tenant=${NAMESPACE_ID}" \ + --data-urlencode "group=${group}" \ + --data-urlencode "dataId=${data_id}" \ + --data-urlencode "type=yaml" \ + --data-urlencode "content@${file_path}" >/dev/null + fi + + printf 'published %s/%s\n' "$group" "$data_id" +} + +while IFS= read -r file_path; do + [ -f "$file_path" ] || continue + group_name="$(basename "$(dirname "$file_path")")" + data_id="$(basename "$file_path")" + publish_file "$file_path" "$group_name" "$data_id" +done < <(find "$TMP_DIR" -type f -name '*.yml' | sort) diff --git a/localbox/restart_local_service.sh b/localbox/restart_local_service.sh new file mode 100755 index 0000000..e409498 --- /dev/null +++ b/localbox/restart_local_service.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +load_local_env +wait_for_docker + +REBUILD=false + +usage() { + cat <<'EOF' +用法: + ./restart_local_service.sh live + ./restart_local_service.sh --rebuild auth + ./restart_local_service.sh golang + +支持的服务: + gateway auth external other live order wallet console visual-monitor scheduling game-fruit golang + mysql redis mongo nacos zookeeper + rocketmq rocketmq-namesrv rocketmq-broker rocketmq-proxy +EOF +} + +while [ "$#" -gt 0 ]; do + case "$1" in + --rebuild) + REBUILD=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + break + ;; + esac +done + +if [ "$#" -ne 1 ]; then + usage >&2 + exit 1 +fi + +SERVICE="$1" + +if [ "$SERVICE" = "rocketmq-proxy" ]; then + SERVICE="rocketmq-proxy" +fi + +case "$SERVICE" in + gateway|auth|external|other|live|order|wallet|console|visual-monitor|scheduling|game-fruit|golang|mysql|redis|mongo|nacos|zookeeper|rocketmq|rocketmq-namesrv|rocketmq-broker|rocketmq-proxy) + ;; + *) + echo "unknown service: $SERVICE" >&2 + usage >&2 + exit 1 + ;; +esac + +if [ "$REBUILD" = true ] && is_java_service "$SERVICE"; then + "$SCRIPT_DIR/build_local_backend.sh" "$SERVICE" +fi + +if [ "$SERVICE" = "rocketmq" ]; then + compose up -d --remove-orphans --force-recreate rocketmq-namesrv rocketmq-init rocketmq-broker rocketmq-proxy +elif [ "$SERVICE" = "other" ] && ! local_rocketmq_disabled; then + compose up -d --remove-orphans rocketmq-namesrv rocketmq-init rocketmq-broker rocketmq-proxy + wait_local_rocketmq + compose up -d --no-deps --force-recreate "$SERVICE" +elif [ "$SERVICE" = "rocketmq-broker" ]; then + compose up -d --remove-orphans rocketmq-namesrv rocketmq-init rocketmq-broker +elif [ "$SERVICE" = "rocketmq-proxy" ]; then + compose up -d --remove-orphans rocketmq-namesrv rocketmq-init rocketmq-broker rocketmq-proxy +else + compose up -d --no-deps --force-recreate "$SERVICE" +fi + +case "$SERVICE" in + gateway|auth|external|other|live|order|wallet|console|visual-monitor|scheduling|game-fruit|golang) + wait_service_port "$SERVICE" 120 + ;; + mysql) + wait_container_healthy chatapp3-local-mysql 120 + ;; + redis) + wait_container_healthy chatapp3-local-redis 120 + ;; + mongo) + wait_container_healthy chatapp3-local-mongo 120 + ;; + nacos) + require_env LIKEI_LOCAL_NACOS_PORT + wait_http "http://127.0.0.1:${LIKEI_LOCAL_NACOS_PORT}/nacos/" 120 + ;; + zookeeper) + wait_container_healthy chatapp3-local-zookeeper 120 + ;; + rocketmq) + wait_local_rocketmq + ;; + rocketmq-namesrv) + require_env LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT + wait_container_healthy chatapp3-local-rocketmq-namesrv 120 + wait_tcp_port 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" 120 + ;; + rocketmq-broker) + wait_container_healthy chatapp3-local-rocketmq-broker 120 + wait_rocketmq_cluster 120 + ;; + rocketmq-proxy) + require_env LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT + wait_container_healthy chatapp3-local-rocketmq-proxy 120 + wait_tcp_port 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" 120 + ;; +esac + +if [ "$SERVICE" = "rocketmq" ]; then + compose ps rocketmq-namesrv rocketmq-broker rocketmq-proxy +else + compose ps "$SERVICE" +fi diff --git a/localbox/start_local_services.sh b/localbox/start_local_services.sh new file mode 100755 index 0000000..3f86e30 --- /dev/null +++ b/localbox/start_local_services.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +BUILD_SCRIPT="$SCRIPT_DIR/build_local_backend.sh" +PUBLISH_SCRIPT="$SCRIPT_DIR/publish_local_nacos_configs.sh" + +SKIP_BUILD=false +INFRA_ONLY=false + +usage() { + cat <<'EOF' +用法: + ./start_local_services.sh + ./start_local_services.sh --skip-build + ./start_local_services.sh --infra-only +EOF +} + +while [ "$#" -gt 0 ]; do + case "$1" in + --skip-build) + SKIP_BUILD=true + ;; + --infra-only) + INFRA_ONLY=true + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "unknown option: $1" >&2 + usage >&2 + exit 1 + ;; + esac + shift +done + +load_local_env +wait_for_docker + +if [ "$SKIP_BUILD" = false ] && [ "$INFRA_ONLY" = false ]; then + java_major="$(java_major_version || true)" + if [ "$java_major" = "17" ]; then + "$BUILD_SCRIPT" + else + if all_local_java_jars_present; then + echo "detected Java ${java_major:-unknown}; local rebuild requires JDK 17" >&2 + echo "to intentionally reuse the current jars, rerun ./start_local_services.sh --skip-build" >&2 + else + echo "local Java jars are missing and the current machine is not using JDK 17" >&2 + echo "please switch to JDK 17 and rerun ./start_local_services.sh, or prebuild the jars first" >&2 + fi + exit 1 + fi +fi + +compose up -d mysql redis mongo nacos zookeeper + +if ! local_rocketmq_disabled; then + compose up -d --remove-orphans rocketmq-namesrv rocketmq-init rocketmq-broker rocketmq-proxy +fi + +wait_container_healthy chatapp3-local-mysql 120 +wait_container_healthy chatapp3-local-redis 120 +wait_container_healthy chatapp3-local-mongo 120 +echo "waiting for nacos..." +require_env LIKEI_LOCAL_NACOS_PORT +wait_http "http://127.0.0.1:${LIKEI_LOCAL_NACOS_PORT}/nacos/" 120 +wait_local_rocketmq + +"$PUBLISH_SCRIPT" + +if [ "$INFRA_ONLY" = false ]; then + compose up -d --force-recreate \ + gateway auth external other live order wallet console visual-monitor scheduling game-fruit golang + + for service in gateway auth other live order wallet console external visual-monitor scheduling game-fruit golang; do + wait_service_port "$service" 120 + done +fi + +compose ps