From e6404f6deedaa02cf06745d3a4588cfbfc78062f Mon Sep 17 00:00:00 2001 From: skeleton Date: Tue, 15 Oct 2024 09:53:29 +0000 Subject: [PATCH 01/23] =?UTF-8?q?=E6=9B=B4=E6=96=B0.gitlab-ci.yml=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 74 ++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56cb3c9..fbde051 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,10 @@ stages: - build - - deploy - - push + - save + - sync variables: ProjectPath: "mongo.games.com/game" - DeployPath: "mongo.games.com/deploy" default: tags: @@ -33,47 +32,58 @@ build-job: done < shell/programs.txt deploy-job: - stage: deploy + stage: save script: - # 拉取 - - echo "拉取deploy" - - cd $GOPATH/src/$DeployPath - - git checkout $CI_COMMIT_REF_NAME - - git pull - - # 拷贝data目录 - - echo '拷贝data目录' - cd $GOPATH/src/$ProjectPath - - cp -rfvp data/* $GOPATH/src/$DeployPath/data - + # 拷贝文件 + - echo '拷贝文件' + - mkdir -p ./temp + - mkdir -p ./temp/data + - cp -rfp ./data/* ./temp/data # 删除自定义配置 - echo '删除自定义配置' - | while IFS= read -r line do - echo "删除 $line 配置" - rm $GOPATH/src/$DeployPath/data/$line - done < shell/exclude.txt - + echo "删除 $line 配置" + rm ./temp/data/$line + done < ./shell/exclude.txt # 拷贝可执行程序 - echo '拷贝可执行程序' - | while IFS= read -r line do - echo "拷贝 $line" - cp -rf $line/$line $GOPATH/src/$DeployPath/ - echo "删除 $line" - rm -rf $line/$line - done < shell/programs.txt + echo "拷贝 $line" + mv ./$line/$line ./temp/$line + done < ./shell/programs.txt push_job: - stage: push + stage: sync script: - # 提交代码 - - echo '提交代码' - - cd $GOPATH/src/$DeployPath - - git config user.email "ci@example.com" # 设置提交者的 email - - git config user.name "GitLab CI" # 设置提交者的名称 - - git add . - - git commit -m "auto commit pipelineId $CI_PIPELINE_ID" - - git push origin $CI_COMMIT_REF_NAME \ No newline at end of file + - cd $GOPATH/src/$ProjectPath + - | + if [ "$CI_COMMIT_BRANCH" == "develop" ]; then + SSH_PRIVATE_KEY="$SSH_PRIVATE_KEY_DEVELOP" + REMOTE_HOST="$REMOTE_HOST_DEVELOP" + REMOTE_USER="$REMOTE_USER_DEVELOP" + REMOTE_PATH="$REMOTE_PATH_DEVELOP" + elif [ "$CI_COMMIT_BRANCH" == "release" ]; then + SSH_PRIVATE_KEY="$SSH_PRIVATE_KEY_BETA" + REMOTE_HOST="$REMOTE_HOST_BETA" + REMOTE_USER="$REMOTE_USER_BETA" + REMOTE_PATH="$REMOTE_PATH_BETA" + else + echo "不支持的分支"; + exit 1; + fi + + - echo "Setting up SSH keys..." + # 设置 .ssh 目录并写入 SSH 私钥 + - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - ssh-keyscan -H "$REMOTE_HOST" >> ~/.ssh/known_hosts + + # 使用 rsync 将文件同步到远程服务器 + - echo "Deploying to remote server using rsync..." + - rsync -avz --delete build/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH \ No newline at end of file From ba552f830b73828055df2fd413043adbf84ab25d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Sat, 26 Oct 2024 09:03:27 +0800 Subject: [PATCH 02/23] no message --- worldsrv/scene.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldsrv/scene.go b/worldsrv/scene.go index 753c59b..e245480 100644 --- a/worldsrv/scene.go +++ b/worldsrv/scene.go @@ -65,7 +65,7 @@ type Scene struct { *serverproto.CustomParam // 房卡场参数 *serverproto.MatchParam // 比赛场参数 *webapiproto.RoomConfigSystem // 系统竞技馆房间 - CloseCtrl bool // 调控开关 + CloseCtrl bool // 调控开关 csp *CoinScenePool // 所在场景池 hp *HundredSceneMgr // 百人场房间池 From 239d88d4ad124ff3647a87551633733ecf3a76e0 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 29 Oct 2024 14:55:08 +0800 Subject: [PATCH 03/23] update ci --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bd54444..46b08a4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -112,7 +112,7 @@ sync_job: # 使用 rsync 将文件同步到远程服务器 - echo "同步到服务器" - echo "Deploying to remote server using rsync..." - - rsync -avz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_DEPLOY_PATH + - rsync -avz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:/home/game # 触发部署 - "curl -X POST --fail -F token=$SERVER_CI_TOKEN -F ref=release -F variables[ServerName]=$ServerName https://git.pogorockgames.com/api/v4/projects/31/trigger/pipeline" From f08fdc1309a9f0d9f22ce599e3818d5dd8a15987 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 29 Oct 2024 15:07:50 +0800 Subject: [PATCH 04/23] update ci --- .gitlab-ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46b08a4..a1bceb1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,8 @@ stages: variables: ProjectPath: "mongo.games.com/game" + BetaBinPath: "/home/centos/" + DevelopBinPath: "/home/game/" default: tags: @@ -92,11 +94,13 @@ sync_job: REMOTE_HOST="$REMOTE_HOST_DEVELOP"; REMOTE_USER="$REMOTE_USER_DEVELOP"; ServerName="develop"; + BinPath="$DevelopBinPath"; elif [ "$CI_COMMIT_BRANCH" == "release" ]; then SSH_PRIVATE_KEY="$SSH_PRIVATE_KEY_BETA"; REMOTE_HOST="$REMOTE_HOST_BETA"; REMOTE_USER="$REMOTE_USER_BETA"; ServerName="beta"; + BinPath="$BetaBinPath"; else echo "不支持的分支"; exit 1; @@ -112,7 +116,7 @@ sync_job: # 使用 rsync 将文件同步到远程服务器 - echo "同步到服务器" - echo "Deploying to remote server using rsync..." - - rsync -avz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:/home/game + - rsync -avz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:$BinPath # 触发部署 - "curl -X POST --fail -F token=$SERVER_CI_TOKEN -F ref=release -F variables[ServerName]=$ServerName https://git.pogorockgames.com/api/v4/projects/31/trigger/pipeline" From d30de2a458c53b2892c61fe1acf21345180cf907 Mon Sep 17 00:00:00 2001 From: skeleton Date: Fri, 1 Nov 2024 03:34:49 +0000 Subject: [PATCH 05/23] =?UTF-8?q?=E6=9B=B4=E6=96=B0.gitlab-ci.yml=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1bceb1..3918b8e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: variables: ProjectPath: "mongo.games.com/game" - BetaBinPath: "/home/centos/" + BetaBinPath: "/home/game/" DevelopBinPath: "/home/game/" default: @@ -115,8 +115,8 @@ sync_job: # 使用 rsync 将文件同步到远程服务器 - echo "同步到服务器" - - echo "Deploying to remote server using rsync..." - - rsync -avz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:$BinPath + - echo "Deploying to remote server using rsync...$BinPath" + - rsync -rvz --delete ./temp/ $REMOTE_USER@$REMOTE_HOST:$BinPath # 触发部署 - "curl -X POST --fail -F token=$SERVER_CI_TOKEN -F ref=release -F variables[ServerName]=$ServerName https://git.pogorockgames.com/api/v4/projects/31/trigger/pipeline" From f0e18b16d08b77d196736596b92e6832f1cd6a73 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 13 Nov 2024 09:22:01 +0800 Subject: [PATCH 06/23] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/action_friend.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/worldsrv/action_friend.go b/worldsrv/action_friend.go index c6fa651..e627340 100644 --- a/worldsrv/action_friend.go +++ b/worldsrv/action_friend.go @@ -15,7 +15,6 @@ import ( "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/friend" - "mongo.games.com/game/protocol/welfare" "mongo.games.com/game/srvdata" ) @@ -603,29 +602,6 @@ func (this *CSFuzzyQueryPlayerHandler) Process(s *netlib.Session, packetid int, return nil } - pack2 := &welfare.NotifyLotteryAward{ - Info: &welfare.LotteryInfo{ - Id: 45, - StartTs: time.Now().Unix(), - Index: int32(5), - Award: []*welfare.PropInfo{ - { - ItemId: 100001, - ItemNum: 100, - }, - }, - SnId: p.SnId, - Name: p.Name, - RoleId: p.Roles.ModId, - Price: 1000, - WinCode: "123456", - }, - } - - // 广播中奖结果 - PlayerMgrSington.BroadcastMessageToPlatform(p.Platform, int(welfare.SPacketID_PACKET_NotifyLotteryAward), pack2) - logger.Logger.Tracef("广播中奖信息: %v", pack2) - queryContent := msg.GetQueryContent() if utf8.RuneCountInString(queryContent) < 3 { return nil From 28b6cb6a85ba589a6f96d4d89d37a10c1827927e Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 13 Nov 2024 11:17:07 +0800 Subject: [PATCH 07/23] =?UTF-8?q?=E6=8A=BD=E5=A5=96=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA=E5=8F=91=E5=A5=96=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/action_player.go | 4 +++- worldsrv/lotterymgr.go | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/worldsrv/action_player.go b/worldsrv/action_player.go index 4c76e04..0bf4180 100644 --- a/worldsrv/action_player.go +++ b/worldsrv/action_player.go @@ -3181,7 +3181,9 @@ func CSUpdateAttribute(s *netlib.Session, packetId int, data interface{}, sid in } } else { pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess - p.GuideData[msg.GuideId] = int32(msg.Param[0]) + if len(msg.Param) > 0 { + p.GuideData[msg.GuideId] = int32(msg.Param[0]) + } send() return nil } diff --git a/worldsrv/lotterymgr.go b/worldsrv/lotterymgr.go index 3833728..4cad494 100644 --- a/worldsrv/lotterymgr.go +++ b/worldsrv/lotterymgr.go @@ -47,6 +47,22 @@ func init() { } } }, + OnMiniTimerFunc: func() { + for i := range LotteryMgrInst.Data { + for k := range LotteryMgrInst.Data[i] { + d := LotteryMgrInst.Data[i][k] + if d == nil { + continue + } + lc := PlatformMgrSingleton.GetLotteryConfig(d.Platform, d.CId) + if lc == nil || lc.GetOn() != common.On { + continue + } + // 随机给机器人发放抽奖码 + d.sendRobotCode(1, 5) + } + } + }, }) } @@ -477,8 +493,6 @@ func (l *LotteryMgr) Update() { if lc == nil || lc.GetOn() != common.On { continue } - // 随机给机器人发放抽奖码 - d.sendRobotCode(1, 5) // 活动结束,开始抽奖 d.Done() // 开始发奖 From d3f276f0bf6948967df472cce8ecfa2c95d89be3 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 11:13:47 +0800 Subject: [PATCH 08/23] =?UTF-8?q?=E5=85=91=E6=8D=A2=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/i18n/languages.json | 7 +- model/message.go | 1 + protocol/webapi/webapi.pb.go | 993 ++++++++++++++++++----------------- protocol/webapi/webapi.proto | 2 + worldsrv/action_shop.go | 12 +- worldsrv/addmail.go | 14 + worldsrv/shopmgr.go | 24 + 7 files changed, 560 insertions(+), 493 deletions(-) diff --git a/data/i18n/languages.json b/data/i18n/languages.json index 904f89e..8a5080c 100644 --- a/data/i18n/languages.json +++ b/data/i18n/languages.json @@ -11,7 +11,8 @@ "PermitAwardTitle": "{\"zh\":\"通行证排行奖励\",\"vi\":\"Vượt qua phần thưởng xếp hạng\",\"en\":\"Pass Ranking Rewards\",\"kh\":\"រង្វាន់ចំណាត់ថ្នាក់ឆ្លងកាត់\"}", "PermitAward": "{\"zh\":\"恭喜您在上个赛季通行证排行中名次达到%v名,排行奖励已发放,请查收\",\"vi\":\"Chúc mừng bạn đã đạt được %v trong bảng xếp hạng vượt qua. Phần thưởng xếp hạng đã được phân phối, vui lòng kiểm tra.\",\"en\":\"Congratulations on reaching %vth place in the pass ranking. Ranking rewards have been issued. Please check.\",\"kh\":\"សូមអបអរសាទរចំពោះការឈានដល់ចំណាត់ថ្នាក់ទី %v ក្នុងចំណាត់ថ្នាក់ឆ្លងកាត់។ រង្វាន់ចំណាត់ថ្នាក់ត្រូវបានចេញ។ សូមត្រួតពិនិត្យ។\"}", "UpgradeTitle": "{\"zh\":\"更新奖励\",\"vi\":\"Phần thưởng cập nhật\",\"en\":\"Update Rewards\",\"kh\":\"រង្វាន់ដំឡើង\"}", - "Upgrade": "{\"zh\":\"感谢您更新客户端,更新奖励已发放至附近,请注意查收\",\"vi\":\"Cảm ơn bạn đã cập nhật ứng dụng khách. Phần thưởng cập nhật đã được phân phối gần đó, vui lòng chú ý kiểm tra nhận\",\"en\":\"Thank you for updating the client. The update reward has been distributed to everyone. Please check it carefully.\",\"kh\":\"អរគុណសម្រាប់ការធ្វើបច្ចុប្បន្នភាពហ្គេម។ រង្វាន់នៃការធ្វើបច្ចុប្បន្នភាពត្រូវបានចែកចាយទៅគ្រប់គ្នា។ សូមពិនិត្យអោយបានច្បាស់លាស់។\"}", - "LotteryTitle": "{\"zh\":\"玩游戏抽奖品\",\"vi\":\"Chơi game rút thưởng\",\"en\":\"Play games, draw prizes\",\"kh\":\"លេងហ្គេម ចាប់រង្វាន់\"}", - "Lottery": "{\"zh\":\"恭喜您在好友房玩游戏抽奖品活动中获得了大奖,奖品随邮件发放,请注意查收\",\"vi\":\"Chúc mừng bạn đã trúng giải thưởng lớn trong hoạt động rút thưởng trò chơi tại phòng bạn bè. Giải thưởng sẽ được gửi qua email, vui lòng kiểm tra cẩn thận.\",\"en\":\"Congratulations on winning the grand prize in the lucky draw activity in the friend room. The prize will be sent via email, please check it carefully.\",\"kh\":\"សូមអបអរសាទរចំពោះការឈ្នះរង្វាន់ធំក្នុងសកម្មភាពចាប់រង្វាន់ក្នុងបន្ទប់មិត្តភ័ក្តិរបស់អ្នក រង្វាន់នឹងត្រូវបានផ្ញើតាមអ៊ីម៉ែល សូមពិនិត្យមើលវាដោយយកចិត្តទុកដាក់។\"}" + "Upgrade": "{\"zh\":\"感谢您更新客户端,更新奖励已发放至附近,请注意查收\",\"vi\":\"Cảm ơn bạn đã cập nhật ứng dụng khách. Phần thưởng cập nhật đã được phân phối gần đó, vui lòng chú ý kiểm tra nhận\",\"en\":\"Thank you for updating the client. The update reward has been distributed to everyone. Please check it carefully.\",\"kh\":\"អរគុណសម្រាប់ការធ្វើបច្ចុប្បន្នភាពហ្គេម។ រង្វាន់នៃការធ្វើបច្ចុប្បន្នភាពត្រូវបានចែកចាយទៅគ្រប់គ្នា។ សូមពិនិត្យអោយបានច្បាស់លាស់។\"}", + "LotteryTitle": "{\"zh\":\"玩游戏抽奖品\",\"vi\":\"Chơi game rút thưởng\",\"en\":\"Play games, draw prizes\",\"kh\":\"លេងហ្គេម ចាប់រង្វាន់\"}", + "Lottery": "{\"zh\":\"恭喜您在好友房玩游戏抽奖品活动中获得了大奖,奖品随邮件发放,请注意查收\",\"vi\":\"Chúc mừng bạn đã trúng giải thưởng lớn trong hoạt động rút thưởng trò chơi tại phòng bạn bè. Giải thưởng sẽ được gửi qua email, vui lòng kiểm tra cẩn thận.\",\"en\":\"Congratulations on winning the grand prize in the lucky draw activity in the friend room. The prize will be sent via email, please check it carefully.\",\"kh\":\"សូមអបអរសាទរចំពោះការឈ្នះរង្វាន់ធំក្នុងសកម្មភាពចាប់រង្វាន់ក្នុងបន្ទប់មិត្តភ័ក្តិរបស់អ្នក រង្វាន់នឹងត្រូវបានផ្ញើតាមអ៊ីម៉ែល សូមពិនិត្យមើលវាដោយយកចិត្តទុកដាក់។\"}", + "TelCodeTitle": "{\"zh\":\"话费卡兑换码\",\"vi\":\"Mã đổi thẻ điện thoại\",\"en\":\"Phone card redemption code\",\"kh\":\"លេខកូដប្រោសលោះកាតទូរស័ព្ទ\"}" } \ No newline at end of file diff --git a/model/message.go b/model/message.go index 651d1b5..2a777f4 100644 --- a/model/message.go +++ b/model/message.go @@ -41,6 +41,7 @@ const ( MSGTYPE_RANK_PermitReward // 通行证排行奖励 MSGTYPE_ClientUpgrade // 客户端升级 MSGTYPE_Lottery // 开奖码抽奖 + MSGTYPE_TelCode // 手机兑换码 ) const ( diff --git a/protocol/webapi/webapi.pb.go b/protocol/webapi/webapi.pb.go index d9b98fa..d8be4c1 100644 --- a/protocol/webapi/webapi.pb.go +++ b/protocol/webapi/webapi.pb.go @@ -6337,8 +6337,10 @@ type SACreateExchangeOrder struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Tag TagCode `protobuf:"varint,1,opt,name=Tag,proto3,enum=webapi.TagCode" json:"Tag,omitempty"` //错误码 - ReturnCPO *ReturnCPO `protobuf:"bytes,2,opt,name=ReturnCPO,proto3" json:"ReturnCPO,omitempty"` + Tag TagCode `protobuf:"varint,1,opt,name=Tag,proto3,enum=webapi.TagCode" json:"Tag,omitempty"` //错误码 + ReturnCPO *ReturnCPO `protobuf:"bytes,2,opt,name=ReturnCPO,proto3" json:"ReturnCPO,omitempty"` + Items []*ItemInfo `protobuf:"bytes,3,rep,name=Items,proto3" json:"Items,omitempty"` // 道具变化 + TelCode string `protobuf:"bytes,4,opt,name=TelCode,proto3" json:"TelCode,omitempty"` // 手机兑换码 } func (x *SACreateExchangeOrder) Reset() { @@ -6387,6 +6389,20 @@ func (x *SACreateExchangeOrder) GetReturnCPO() *ReturnCPO { return nil } +func (x *SACreateExchangeOrder) GetItems() []*ItemInfo { + if x != nil { + return x.Items + } + return nil +} + +func (x *SACreateExchangeOrder) GetTelCode() string { + if x != nil { + return x.TelCode + } + return "" +} + //获取交易订单game_srv/get_exchange_order type ASGetExchangeOrder struct { state protoimpl.MessageState @@ -11178,465 +11194,469 @@ var file_protocol_webapi_webapi_proto_rawDesc = []byte{ 0x70, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x44, 0x50, - 0x72, 0x69, 0x63, 0x65, 0x22, 0x6b, 0x0a, 0x15, 0x53, 0x41, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, - 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, - 0x12, 0x2f, 0x0a, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x50, 0x4f, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x43, 0x50, 0x4f, 0x52, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x50, - 0x4f, 0x22, 0x58, 0x0a, 0x12, 0x41, 0x53, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0xaf, 0x02, 0x0a, 0x11, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, - 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, - 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x52, - 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x6d, - 0x61, 0x72, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x50, 0x61, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4e, 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x58, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x45, 0x58, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x22, 0xdc, 0x01, - 0x0a, 0x12, 0x53, 0x41, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, 0x74, 0x61, 0x6c, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, - 0x07, 0x43, 0x75, 0x72, 0x50, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, - 0x43, 0x75, 0x72, 0x50, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x67, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x50, 0x61, 0x67, 0x65, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x74, - 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, - 0x74, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xe8, 0x01, 0x0a, - 0x12, 0x41, 0x53, 0x55, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x47, - 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x47, 0x6f, - 0x6f, 0x64, 0x73, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4e, 0x65, 0x65, - 0x64, 0x4e, 0x75, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x4e, 0x65, 0x65, 0x64, - 0x4e, 0x75, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x4a, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, - 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x61, 0x73, 0x68, 0x12, - 0x16, 0x0a, 0x06, 0x44, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x06, 0x44, 0x50, 0x72, 0x69, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x12, 0x53, 0x41, 0x55, 0x70, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, - 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, - 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, - 0x73, 0x67, 0x22, 0x43, 0x0a, 0x11, 0x41, 0x53, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x53, 0x68, 0x6f, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x11, 0x53, 0x41, 0x47, 0x65, - 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x68, 0x6f, 0x70, 0x12, 0x21, 0x0a, - 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, - 0x12, 0x28, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x53, 0x68, 0x6f, 0x70, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x57, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x53, 0x68, 0x6f, 0x70, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x52, 0x06, - 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x57, 0x0a, 0x0d, 0x53, 0x41, 0x52, 0x6f, 0x63, 0x6b, - 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, - 0x45, 0x0a, 0x0d, 0x41, 0x53, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x12, 0x10, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x54, - 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x22, 0x42, 0x0a, 0x10, 0x53, 0x41, 0x52, 0x6f, 0x63, 0x6b, - 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, + 0x72, 0x69, 0x63, 0x65, 0x22, 0xad, 0x01, 0x0a, 0x15, 0x53, 0x41, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, + 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, + 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, + 0x67, 0x12, 0x2f, 0x0a, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x50, 0x4f, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x43, 0x50, 0x4f, 0x52, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, + 0x50, 0x4f, 0x12, 0x26, 0x0a, 0x05, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x54, 0x65, + 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x54, 0x65, 0x6c, + 0x43, 0x6f, 0x64, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x41, 0x53, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x4e, 0x0a, 0x10, 0x41, 0x53, - 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4f, 0x75, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x54, 0x61, 0x67, - 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x67, 0x0a, 0x15, 0x41, 0x53, - 0x54, 0x68, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x43, - 0x6f, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x47, 0x61, 0x6d, 0x65, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x47, 0x61, 0x6d, - 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x22, 0x4c, 0x0a, 0x15, 0x53, 0x41, 0x54, 0x68, 0x64, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x03, - 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, - 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, - 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, - 0x67, 0x22, 0xf5, 0x03, 0x0a, 0x0d, 0x53, 0x41, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x68, 0x6f, 0x70, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x68, 0x6f, 0x70, 0x49, 0x64, 0x12, - 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x61, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x4f, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x68, 0x6f, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x53, 0x68, 0x6f, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, - 0x20, 0x03, 0x28, 0x05, 0x52, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x0a, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x22, 0x0a, 0x0c, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, 0x0a, - 0x02, 0x54, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x54, 0x73, 0x12, 0x28, 0x0a, - 0x0f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x44, 0x12, - 0x18, 0x0a, 0x07, 0x42, 0x75, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x07, 0x42, 0x75, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x45, 0x0a, 0x0d, 0x41, 0x53, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x61, - 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, - 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x10, - 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, - 0x22, 0x54, 0x0a, 0x12, 0x53, 0x41, 0x57, 0x65, 0x62, 0x41, 0x50, 0x49, 0x53, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x43, 0x42, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x43, 0x42, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x02, 0x54, 0x73, 0x22, 0x66, 0x0a, 0x12, 0x41, 0x53, 0x57, 0x65, 0x62, 0x41, - 0x50, 0x49, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, - 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x45, 0x72, - 0x72, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x45, 0x72, 0x72, 0x4d, - 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, - 0x0a, 0x11, 0x41, 0x53, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, - 0x48, 0x0a, 0x11, 0x53, 0x41, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x1e, 0x0a, 0x0a, 0x41, 0x53, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x41, 0x0a, 0x0a, 0x53, 0x41, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, + 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0xaf, + 0x02, 0x0a, 0x11, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x79, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x50, 0x61, 0x79, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4e, 0x75, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x45, 0x58, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x45, 0x58, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x65, + 0x6c, 0x49, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, + 0x22, 0xdc, 0x01, 0x0a, 0x12, 0x53, 0x41, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, - 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, - 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x7d, 0x0a, 0x09, - 0x41, 0x53, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x50, 0x68, - 0x6f, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x22, 0x40, 0x0a, 0x09, 0x53, - 0x41, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, - 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, - 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0xb9, 0x01, - 0x0a, 0x13, 0x41, 0x53, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x77, 0x61, 0x72, - 0x64, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x44, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x44, 0x12, 0x14, 0x0a, - 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x4d, 0x6f, - 0x6e, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x54, 0x65, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x43, 0x61, 0x72, 0x64, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x74, 0x0a, 0x13, 0x53, 0x41, 0x47, - 0x65, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, - 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, - 0x54, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x4d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, - 0x4f, 0x0a, 0x0b, 0x41, 0x53, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x6c, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x65, 0x6c, - 0x22, 0x42, 0x0a, 0x0b, 0x53, 0x41, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x6c, 0x12, - 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, - 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, - 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x4d, 0x73, 0x67, 0x22, 0x22, 0x0a, 0x0e, 0x41, 0x53, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x67, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x65, 0x6c, 0x22, 0x77, 0x0a, 0x0e, 0x53, 0x41, 0x47, 0x65, - 0x74, 0x49, 0x6d, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, - 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, - 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x1c, 0x0a, - 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x43, - 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, - 0x67, 0x22, 0x40, 0x0a, 0x0e, 0x41, 0x53, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, - 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, - 0x6e, 0x69, 0x64, 0x22, 0x45, 0x0a, 0x0e, 0x53, 0x41, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x44, 0x0a, 0x12, 0x41, 0x53, - 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, - 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, - 0x22, 0x5d, 0x0a, 0x12, 0x53, 0x41, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, - 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x4c, - 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x22, - 0x9d, 0x01, 0x0a, 0x0d, 0x41, 0x53, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x79, 0x49, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x2c, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x16, 0x0a, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, - 0x44, 0x0a, 0x0d, 0x53, 0x41, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x79, 0x49, 0x64, + 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x54, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x75, 0x72, 0x50, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x07, 0x43, 0x75, 0x72, 0x50, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, + 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x50, + 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x50, 0x61, 0x67, + 0x65, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x37, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, + 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x65, 0x62, 0x61, + 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, + 0xe8, 0x01, 0x0a, 0x12, 0x41, 0x53, 0x55, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x4e, 0x65, 0x65, 0x64, 0x4e, 0x75, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x4e, + 0x65, 0x65, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x4a, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x4a, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x43, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x43, 0x61, + 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x44, 0x50, 0x72, 0x69, 0x63, 0x65, 0x22, 0x49, 0x0a, 0x12, 0x53, 0x41, + 0x55, 0x70, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x4d, 0x53, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, - 0x53, 0x6e, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x53, 0x41, 0x53, 0x4d, 0x53, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, - 0x53, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x4d, 0x53, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, - 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, - 0x4d, 0x73, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x33, - 0x0a, 0x07, 0x53, 0x4d, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x6d, 0x73, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x6d, 0x73, 0x4e, - 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x0a, 0x41, 0x53, 0x41, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x6f, - 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, - 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, - 0x64, 0x22, 0x46, 0x0a, 0x14, 0x41, 0x53, 0x50, 0x6f, 0x70, 0x55, 0x70, 0x57, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x22, 0xa4, 0x01, 0x0a, 0x14, 0x53, 0x41, - 0x50, 0x6f, 0x70, 0x55, 0x70, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, - 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, - 0x49, 0x64, 0x12, 0x27, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x03, 0x54, - 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, + 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x43, 0x0a, 0x11, 0x41, 0x53, 0x47, 0x65, 0x74, 0x45, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x68, 0x6f, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x11, 0x53, + 0x41, 0x47, 0x65, 0x74, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x68, 0x6f, 0x70, + 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, + 0x54, 0x61, 0x67, 0x12, 0x28, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x53, 0x68, 0x6f, 0x70, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2a, 0x0a, + 0x06, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x68, 0x6f, 0x70, 0x57, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x52, 0x06, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x57, 0x0a, 0x0d, 0x53, 0x41, 0x52, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x22, 0x45, 0x0a, 0x0d, 0x41, 0x53, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x22, 0x42, 0x0a, 0x10, 0x53, 0x41, 0x52, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4f, 0x75, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x6e, 0x69, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x4e, 0x0a, + 0x10, 0x41, 0x53, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4f, 0x75, + 0x74, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, + 0x54, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x4d, + 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x67, 0x0a, + 0x15, 0x41, 0x53, 0x54, 0x68, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x42, 0x61, 0x73, 0x65, 0x47, 0x61, + 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x61, 0x73, 0x65, + 0x47, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x4c, 0x0a, 0x15, 0x53, 0x41, 0x54, 0x68, 0x64, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x12, + 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, + 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, + 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x4d, 0x73, 0x67, 0x22, 0xf5, 0x03, 0x0a, 0x0d, 0x53, 0x41, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x68, + 0x6f, 0x70, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x53, 0x68, 0x6f, 0x70, + 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, + 0x0a, 0x0a, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x54, 0x61, 0x67, 0x12, 0x0e, + 0x0a, 0x02, 0x4f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x68, 0x6f, 0x70, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x53, 0x68, 0x6f, 0x70, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0c, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, + 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x54, 0x73, + 0x12, 0x28, 0x0a, 0x0f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x49, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x45, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, + 0x44, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x42, 0x75, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x07, 0x42, 0x75, 0x79, 0x54, 0x79, 0x70, 0x65, 0x22, 0x45, 0x0a, 0x0d, + 0x41, 0x53, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x10, 0x0a, + 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, + 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, + 0x67, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x55, 0x72, 0x6c, 0x22, 0x54, 0x0a, 0x12, 0x53, 0x41, 0x57, 0x65, 0x62, 0x41, 0x50, 0x49, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x42, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x43, 0x42, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x54, 0x73, 0x22, 0x66, 0x0a, 0x12, 0x41, 0x53, 0x57, + 0x65, 0x62, 0x41, 0x50, 0x49, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x12, + 0x1c, 0x0a, 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x45, + 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x5f, 0x0a, 0x11, 0x41, 0x53, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x22, 0x48, 0x0a, 0x11, 0x53, 0x41, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, + 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x1e, 0x0a, 0x0a, + 0x41, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x41, 0x0a, 0x0a, + 0x53, 0x41, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, + 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, + 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, + 0x7d, 0x0a, 0x09, 0x41, 0x53, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x22, 0x40, + 0x0a, 0x09, 0x53, 0x41, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x03, 0x54, + 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, - 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, - 0x22, 0x83, 0x01, 0x0a, 0x0b, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, - 0x55, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x12, - 0x0a, 0x04, 0x53, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6f, - 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x07, 0x50, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, - 0x47, 0x61, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x47, - 0x61, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x22, 0x24, 0x0a, 0x0a, 0x41, 0x53, 0x52, 0x6f, 0x6f, 0x6d, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x22, 0x5d, 0x0a, 0x09, - 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x6f, 0x75, - 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, - 0x0e, 0x0a, 0x02, 0x54, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x54, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0x7c, 0x0a, 0x0a, 0x53, - 0x41, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, + 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, + 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x41, 0x53, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, + 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x74, 0x65, 0x6d, + 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x44, + 0x12, 0x14, 0x0a, 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x65, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x61, 0x72, 0x64, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x43, 0x61, 0x72, 0x64, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x74, 0x0a, 0x13, + 0x53, 0x41, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x77, 0x61, 0x72, 0x64, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4d, 0x6f, + 0x6e, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, + 0x73, 0x67, 0x22, 0x4f, 0x0a, 0x0b, 0x41, 0x53, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, + 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, + 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x54, 0x65, 0x6c, 0x22, 0x42, 0x0a, 0x0b, 0x53, 0x41, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x22, 0x0a, 0x0e, 0x41, 0x53, 0x47, 0x65, 0x74, + 0x49, 0x6d, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x65, 0x6c, 0x22, 0x77, 0x0a, 0x0e, 0x53, + 0x41, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x67, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x21, 0x0a, + 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, + 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, + 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, + 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x4d, 0x73, 0x67, 0x22, 0x40, 0x0a, 0x0e, 0x41, 0x53, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x22, 0x45, 0x0a, 0x0e, 0x53, 0x41, 0x50, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, + 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, + 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x44, 0x0a, + 0x12, 0x41, 0x53, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, + 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, + 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, + 0x6e, 0x49, 0x64, 0x22, 0x5d, 0x0a, 0x12, 0x53, 0x41, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x12, - 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, - 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x48, 0x0a, 0x16, 0x41, 0x53, 0x47, - 0x65, 0x74, 0x44, 0x6f, 0x6c, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x22, 0x74, 0x0a, 0x16, 0x53, 0x41, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6c, 0x6c, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, - 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, - 0x12, 0x37, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0d, 0x41, 0x53, 0x53, - 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x04, - 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x79, 0x52, - 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x47, 0x0a, 0x0b, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, - 0x74, 0x65, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x02, 0x54, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x6d, 0x67, 0x55, 0x72, 0x6c, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x49, 0x6d, 0x67, 0x55, 0x72, 0x6c, 0x22, 0x44, - 0x0a, 0x0d, 0x53, 0x41, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, - 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, - 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, - 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x4d, 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x0d, 0x41, 0x53, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x4d, - 0x53, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4c, 0x69, + 0x6e, 0x6b, 0x22, 0x9d, 0x01, 0x0a, 0x0d, 0x41, 0x53, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, + 0x42, 0x79, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2c, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, + 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x6d, 0x61, + 0x72, 0x6b, 0x22, 0x44, 0x0a, 0x0d, 0x53, 0x41, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x42, + 0x79, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x4d, + 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x53, 0x41, 0x53, 0x4d, + 0x53, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x53, + 0x4d, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x03, + 0x54, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, + 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, + 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, + 0x67, 0x22, 0x33, 0x0a, 0x07, 0x53, 0x4d, 0x53, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, + 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x53, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, + 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x0a, 0x41, 0x53, 0x41, 0x77, 0x61, 0x72, + 0x64, 0x4c, 0x6f, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x53, 0x6e, 0x49, 0x64, 0x22, 0x46, 0x0a, 0x14, 0x41, 0x53, 0x50, 0x6f, 0x70, 0x55, 0x70, 0x57, + 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x22, 0xa4, 0x01, 0x0a, + 0x14, 0x53, 0x41, 0x50, 0x6f, 0x70, 0x55, 0x70, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x54, 0x65, 0x6c, 0x22, 0x44, 0x0a, 0x0d, 0x53, 0x41, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x4d, 0x53, - 0x43, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0xb6, 0x01, 0x0a, 0x0a, 0x41, 0x53, - 0x57, 0x65, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x4d, 0x53, 0x43, - 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x4d, 0x53, 0x43, 0x6f, - 0x64, 0x65, 0x22, 0x71, 0x0a, 0x0a, 0x53, 0x41, 0x57, 0x65, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, - 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, - 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x53, 0x6e, 0x49, 0x64, 0x22, 0x9d, 0x02, 0x0a, 0x13, 0x41, 0x53, 0x57, 0x65, 0x62, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x0e, 0x0a, - 0x02, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x12, 0x1a, 0x0a, - 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x6f, 0x62, - 0x69, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x6f, 0x62, 0x69, 0x6c, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x45, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, - 0x54, 0x65, 0x6c, 0x49, 0x64, 0x22, 0x89, 0x01, 0x0a, 0x13, 0x53, 0x41, 0x57, 0x65, 0x62, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x0a, - 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, - 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x41, 0x53, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, - 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, - 0x64, 0x22, 0x57, 0x0a, 0x0c, 0x53, 0x41, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, - 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x7d, 0x0a, 0x0f, 0x41, 0x53, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x4f, - 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x22, 0x5a, 0x0a, 0x0f, 0x53, 0x41, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x03, + 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, + 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, + 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, + 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x4d, 0x73, 0x67, 0x22, 0x83, 0x01, 0x0a, 0x0b, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, + 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x53, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x50, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, 0x12, + 0x18, 0x0a, 0x07, 0x47, 0x61, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x07, 0x47, 0x61, 0x69, 0x6e, 0x4e, 0x75, 0x6d, 0x22, 0x24, 0x0a, 0x0a, 0x41, 0x53, 0x52, + 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x22, + 0x5d, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, + 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, + 0x54, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x03, 0x52, 0x05, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x49, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x22, 0x7c, + 0x0a, 0x0a, 0x53, 0x41, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, - 0x67, 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0xdc, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, - 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x49, 0x47, 0x4e, 0x5f, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x52, 0x4f, 0x54, 0x4f, - 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x12, 0x12, 0x0a, - 0x0e, 0x4a, 0x59, 0x42, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x4a, 0x59, 0x42, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x45, 0x58, - 0x49, 0x53, 0x54, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x79, 0x5f, 0x4e, 0x6f, - 0x74, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x45, 0x78, 0x69, 0x73, 0x74, 0x10, - 0x09, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x46, - 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x65, 0x6c, 0x4e, 0x6f, 0x74, - 0x42, 0x69, 0x6e, 0x64, 0x10, 0x0b, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x10, 0x0c, 0x2a, 0xb4, 0x02, 0x0a, 0x12, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x4f, - 0x50, 0x52, 0x43, 0x5f, 0x53, 0x75, 0x63, 0x65, 0x73, 0x73, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, - 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, - 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x56, 0x43, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, - 0x75, 0x67, 0x68, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x10, 0x03, 0x12, 0x1a, 0x0a, - 0x16, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x6f, - 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x4f, 0x50, 0x52, - 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x74, - 0x74, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x53, 0x6f, 0x6c, 0x64, 0x4f, 0x75, 0x74, 0x10, 0x06, 0x12, 0x19, 0x0a, - 0x15, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x41, 0x63, 0x63, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, 0x4f, 0x50, 0x52, 0x43, - 0x5f, 0x4a, 0x43, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, - 0x08, 0x12, 0x1a, 0x0a, 0x16, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x56, 0x69, 0x70, 0x4c, 0x65, 0x76, - 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x09, 0x12, 0x13, 0x0a, - 0x0f, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x4e, 0x6f, 0x74, 0x53, 0x49, 0x4d, 0x43, 0x6f, 0x64, 0x65, - 0x10, 0x0a, 0x12, 0x17, 0x0a, 0x13, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x44, 0x43, 0x6f, 0x69, 0x6e, - 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x0b, 0x42, 0x26, 0x5a, 0x24, 0x6d, - 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x61, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x77, 0x65, 0x62, - 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, + 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x6f, 0x75, + 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x48, 0x0a, 0x16, + 0x41, 0x53, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x6c, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x74, 0x0a, 0x16, 0x53, 0x41, 0x47, 0x65, 0x74, 0x44, + 0x6f, 0x6c, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, + 0x54, 0x61, 0x67, 0x12, 0x37, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, + 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0d, + 0x41, 0x53, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, 0x1a, 0x0a, + 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x6f, 0x67, + 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x6f, 0x67, 0x49, 0x64, 0x12, + 0x27, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, + 0x72, 0x79, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x47, 0x0a, 0x0b, 0x53, 0x68, 0x6f, 0x77, + 0x4c, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x02, 0x54, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x6d, 0x67, + 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x49, 0x6d, 0x67, 0x55, 0x72, + 0x6c, 0x22, 0x44, 0x0a, 0x0d, 0x53, 0x41, 0x53, 0x68, 0x6f, 0x77, 0x4c, 0x6f, 0x74, 0x74, 0x65, + 0x72, 0x79, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0x3d, 0x0a, 0x0d, 0x41, 0x53, 0x53, 0x65, 0x6e, + 0x64, 0x53, 0x4d, 0x53, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x54, 0x65, 0x6c, 0x22, 0x44, 0x0a, 0x0d, 0x53, 0x41, 0x53, 0x65, 0x6e, 0x64, + 0x53, 0x4d, 0x53, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, + 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x22, 0xb6, 0x01, 0x0a, + 0x0a, 0x41, 0x53, 0x57, 0x65, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x1a, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x53, + 0x4d, 0x53, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x53, 0x4d, + 0x53, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x71, 0x0a, 0x0a, 0x53, 0x41, 0x57, 0x65, 0x62, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x22, 0x9d, 0x02, 0x0a, 0x13, 0x41, 0x53, 0x57, + 0x65, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, + 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, + 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x26, + 0x0a, 0x0e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, + 0x0a, 0x0c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x54, 0x65, 0x6c, 0x49, 0x64, 0x22, 0x89, 0x01, 0x0a, 0x13, 0x53, 0x41, 0x57, + 0x65, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x12, 0x2c, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x1a, + 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x02, 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x41, 0x53, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x53, 0x6e, 0x49, 0x64, 0x22, 0x57, 0x0a, 0x0c, 0x53, 0x41, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x0f, 0x2e, 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, + 0x64, 0x65, 0x52, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x69, 0x73, + 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x7d, 0x0a, + 0x0f, 0x41, 0x53, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, + 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x4f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x12, 0x0e, 0x0a, 0x02, + 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x22, 0x5a, 0x0a, 0x0f, + 0x53, 0x41, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x21, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x77, + 0x65, 0x62, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x61, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x03, 0x54, + 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0xdc, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x67, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x49, + 0x47, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x52, + 0x4f, 0x54, 0x4f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, + 0x12, 0x12, 0x0a, 0x0e, 0x4a, 0x59, 0x42, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x52, 0x52, + 0x4f, 0x52, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x4a, 0x59, 0x42, 0x5f, 0x43, 0x4f, 0x44, 0x45, + 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x79, + 0x5f, 0x4e, 0x6f, 0x74, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x45, 0x78, 0x69, + 0x73, 0x74, 0x10, 0x09, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, + 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x65, 0x6c, + 0x4e, 0x6f, 0x74, 0x42, 0x69, 0x6e, 0x64, 0x10, 0x0b, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x6f, 0x74, + 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x0c, 0x2a, 0xb4, 0x02, 0x0a, 0x12, 0x45, 0x78, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0f, + 0x0a, 0x0b, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x53, 0x75, 0x63, 0x65, 0x73, 0x73, 0x10, 0x00, 0x12, + 0x0e, 0x0a, 0x0a, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x01, 0x12, + 0x17, 0x0a, 0x13, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x56, 0x43, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x74, + 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x50, 0x52, 0x43, + 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x10, 0x03, + 0x12, 0x1a, 0x0a, 0x16, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, + 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x74, 0x74, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x6f, 0x6c, 0x64, 0x4f, 0x75, 0x74, 0x10, 0x06, + 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x63, 0x63, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, 0x4f, + 0x50, 0x52, 0x43, 0x5f, 0x4a, 0x43, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, + 0x67, 0x68, 0x10, 0x08, 0x12, 0x1a, 0x0a, 0x16, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x56, 0x69, 0x70, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x09, + 0x12, 0x13, 0x0a, 0x0f, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x4e, 0x6f, 0x74, 0x53, 0x49, 0x4d, 0x43, + 0x6f, 0x64, 0x65, 0x10, 0x0a, 0x12, 0x17, 0x0a, 0x13, 0x4f, 0x50, 0x52, 0x43, 0x5f, 0x44, 0x43, + 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x10, 0x0b, 0x42, 0x26, + 0x5a, 0x24, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, + 0x77, 0x65, 0x62, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -11902,44 +11922,45 @@ var file_protocol_webapi_webapi_proto_depIdxs = []int32{ 90, // 73: webapi.SACreatePayOrder.ReturnCPO:type_name -> webapi.ReturnCPO 0, // 74: webapi.SACreateExchangeOrder.Tag:type_name -> webapi.TagCode 90, // 75: webapi.SACreateExchangeOrder.ReturnCPO:type_name -> webapi.ReturnCPO - 0, // 76: webapi.SAGetExchangeOrder.Tag:type_name -> webapi.TagCode - 95, // 77: webapi.SAGetExchangeOrder.OrderList:type_name -> webapi.ExchangeOrderInfo - 0, // 78: webapi.SAUpExchangeStatus.Tag:type_name -> webapi.TagCode - 0, // 79: webapi.SAGetExchangeShop.Tag:type_name -> webapi.TagCode - 168, // 80: webapi.SAGetExchangeShop.List:type_name -> webapi.ExchangeShop - 169, // 81: webapi.SAGetExchangeShop.Weight:type_name -> webapi.ShopWeight - 0, // 82: webapi.SAThdUpdatePlayerCoin.Tag:type_name -> webapi.TagCode - 167, // 83: webapi.SACreateOrder.ItemInfo:type_name -> webapi.ItemInfo - 0, // 84: webapi.SACallbackPayment.Tag:type_name -> webapi.TagCode - 0, // 85: webapi.SAResource.Tag:type_name -> webapi.TagCode - 0, // 86: webapi.SASendSms.Tag:type_name -> webapi.TagCode - 0, // 87: webapi.SAGetMatchAwardCode.Tag:type_name -> webapi.TagCode - 0, // 88: webapi.SAUpdateTel.Tag:type_name -> webapi.TagCode - 0, // 89: webapi.SAGetImgVerify.Tag:type_name -> webapi.TagCode - 0, // 90: webapi.SAPlayerDelete.Tag:type_name -> webapi.TagCode - 0, // 91: webapi.SAPlayerInviteLink.Tag:type_name -> webapi.TagCode - 167, // 92: webapi.ASAddItemById.ItemInfo:type_name -> webapi.ItemInfo - 0, // 93: webapi.SAAddItemById.Tag:type_name -> webapi.TagCode - 131, // 94: webapi.SASMSConfig.Info:type_name -> webapi.SMSInfo - 0, // 95: webapi.SASMSConfig.Tag:type_name -> webapi.TagCode - 135, // 96: webapi.SAPopUpWindowsConfig.Info:type_name -> webapi.WindowsInfo - 0, // 97: webapi.SAPopUpWindowsConfig.Tag:type_name -> webapi.TagCode - 0, // 98: webapi.SARoomInfo.Tag:type_name -> webapi.TagCode - 137, // 99: webapi.SARoomInfo.List:type_name -> webapi.RoundInfo - 0, // 100: webapi.SAGetDollExchangeOrder.Tag:type_name -> webapi.TagCode - 95, // 101: webapi.SAGetDollExchangeOrder.OrderList:type_name -> webapi.ExchangeOrderInfo - 142, // 102: webapi.ASShowLottery.List:type_name -> webapi.ShowLottery - 0, // 103: webapi.SAShowLottery.Tag:type_name -> webapi.TagCode - 0, // 104: webapi.SASendSMSCode.Tag:type_name -> webapi.TagCode - 0, // 105: webapi.SAWebLogin.Tag:type_name -> webapi.TagCode - 1, // 106: webapi.SAWebCreateExchange.Tag:type_name -> webapi.ExchangeCreateCode - 0, // 107: webapi.SAGetAddress.Tag:type_name -> webapi.TagCode - 0, // 108: webapi.SAUpdateAddress.Tag:type_name -> webapi.TagCode - 109, // [109:109] is the sub-list for method output_type - 109, // [109:109] is the sub-list for method input_type - 109, // [109:109] is the sub-list for extension type_name - 109, // [109:109] is the sub-list for extension extendee - 0, // [0:109] is the sub-list for field type_name + 167, // 76: webapi.SACreateExchangeOrder.Items:type_name -> webapi.ItemInfo + 0, // 77: webapi.SAGetExchangeOrder.Tag:type_name -> webapi.TagCode + 95, // 78: webapi.SAGetExchangeOrder.OrderList:type_name -> webapi.ExchangeOrderInfo + 0, // 79: webapi.SAUpExchangeStatus.Tag:type_name -> webapi.TagCode + 0, // 80: webapi.SAGetExchangeShop.Tag:type_name -> webapi.TagCode + 168, // 81: webapi.SAGetExchangeShop.List:type_name -> webapi.ExchangeShop + 169, // 82: webapi.SAGetExchangeShop.Weight:type_name -> webapi.ShopWeight + 0, // 83: webapi.SAThdUpdatePlayerCoin.Tag:type_name -> webapi.TagCode + 167, // 84: webapi.SACreateOrder.ItemInfo:type_name -> webapi.ItemInfo + 0, // 85: webapi.SACallbackPayment.Tag:type_name -> webapi.TagCode + 0, // 86: webapi.SAResource.Tag:type_name -> webapi.TagCode + 0, // 87: webapi.SASendSms.Tag:type_name -> webapi.TagCode + 0, // 88: webapi.SAGetMatchAwardCode.Tag:type_name -> webapi.TagCode + 0, // 89: webapi.SAUpdateTel.Tag:type_name -> webapi.TagCode + 0, // 90: webapi.SAGetImgVerify.Tag:type_name -> webapi.TagCode + 0, // 91: webapi.SAPlayerDelete.Tag:type_name -> webapi.TagCode + 0, // 92: webapi.SAPlayerInviteLink.Tag:type_name -> webapi.TagCode + 167, // 93: webapi.ASAddItemById.ItemInfo:type_name -> webapi.ItemInfo + 0, // 94: webapi.SAAddItemById.Tag:type_name -> webapi.TagCode + 131, // 95: webapi.SASMSConfig.Info:type_name -> webapi.SMSInfo + 0, // 96: webapi.SASMSConfig.Tag:type_name -> webapi.TagCode + 135, // 97: webapi.SAPopUpWindowsConfig.Info:type_name -> webapi.WindowsInfo + 0, // 98: webapi.SAPopUpWindowsConfig.Tag:type_name -> webapi.TagCode + 0, // 99: webapi.SARoomInfo.Tag:type_name -> webapi.TagCode + 137, // 100: webapi.SARoomInfo.List:type_name -> webapi.RoundInfo + 0, // 101: webapi.SAGetDollExchangeOrder.Tag:type_name -> webapi.TagCode + 95, // 102: webapi.SAGetDollExchangeOrder.OrderList:type_name -> webapi.ExchangeOrderInfo + 142, // 103: webapi.ASShowLottery.List:type_name -> webapi.ShowLottery + 0, // 104: webapi.SAShowLottery.Tag:type_name -> webapi.TagCode + 0, // 105: webapi.SASendSMSCode.Tag:type_name -> webapi.TagCode + 0, // 106: webapi.SAWebLogin.Tag:type_name -> webapi.TagCode + 1, // 107: webapi.SAWebCreateExchange.Tag:type_name -> webapi.ExchangeCreateCode + 0, // 108: webapi.SAGetAddress.Tag:type_name -> webapi.TagCode + 0, // 109: webapi.SAUpdateAddress.Tag:type_name -> webapi.TagCode + 110, // [110:110] is the sub-list for method output_type + 110, // [110:110] is the sub-list for method input_type + 110, // [110:110] is the sub-list for extension type_name + 110, // [110:110] is the sub-list for extension extendee + 0, // [0:110] is the sub-list for field type_name } func init() { file_protocol_webapi_webapi_proto_init() } diff --git a/protocol/webapi/webapi.proto b/protocol/webapi/webapi.proto index 60a4ff2..4578d63 100644 --- a/protocol/webapi/webapi.proto +++ b/protocol/webapi/webapi.proto @@ -698,6 +698,8 @@ message ASCreateExchangeOrder { message SACreateExchangeOrder { TagCode Tag = 1; //错误码 ReturnCPO ReturnCPO = 2; + repeated ItemInfo Items = 3; // 道具变化 + string TelCode = 4; // 手机兑换码 } //获取交易订单game_srv/get_exchange_order message ASGetExchangeOrder{ diff --git a/worldsrv/action_shop.go b/worldsrv/action_shop.go index 4784920..8ed972e 100644 --- a/worldsrv/action_shop.go +++ b/worldsrv/action_shop.go @@ -735,6 +735,8 @@ func (this *CSUpdateVipShopHandler) Process(s *netlib.Session, packetid int, dat return nil } func init() { + // 商城接口 + // 获取商城商品信息列表 common.RegisterHandler(int(shop.SPacketID_PACKET_CS_SHOP_INFO), &CSShopInfoHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CS_SHOP_INFO), &CSShopInfoPacketFactory{}) @@ -748,20 +750,22 @@ func init() { common.RegisterHandler(int(shop.SPacketID_PACKET_CSGETPAYINFOLIST), &CSGetPayInfoListHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CSGETPAYINFOLIST), &CSGetPayInfoListPacketFactory{}) + // 兑换商城接口 + // 获取商城商品兑换列表 common.RegisterHandler(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGELIST), &CSShopExchangeListHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGELIST), &CSShopExchangeListPacketFactory{}) // 兑换商品(非现金) common.RegisterHandler(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGE), &CSShopExchangeHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGE), &CSShopExchangePacketFactory{}) - // 兑换商品(现金,创建订单) - common.RegisterHandler(int(shop.SPacketID_PACKET_CSPAYINFO), &CSPayInfoHandler{}) - netlib.RegisterFactory(int(shop.SPacketID_PACKET_CSPAYINFO), &CSPayInfoPacketFactory{}) // 获取兑换记录 - //todo 客户端走透传后台获取 common.RegisterHandler(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGERECORD), &CSShopExchangeRecordHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CS_SHOP_EXCHANGERECORD), &CSShopExchangeRecordPacketFactory{}) + // 现金,创建订单(所有现金订单) + common.RegisterHandler(int(shop.SPacketID_PACKET_CSPAYINFO), &CSPayInfoHandler{}) + netlib.RegisterFactory(int(shop.SPacketID_PACKET_CSPAYINFO), &CSPayInfoPacketFactory{}) + //玩家地址操作 common.RegisterHandler(int(shop.SPacketID_PACKET_CSPLAYERADDR), &CSPlayerAddrHandler{}) netlib.RegisterFactory(int(shop.SPacketID_PACKET_CSPLAYERADDR), &CSPlayerAddrPacketFactory{}) diff --git a/worldsrv/addmail.go b/worldsrv/addmail.go index eb111df..379b81d 100644 --- a/worldsrv/addmail.go +++ b/worldsrv/addmail.go @@ -149,3 +149,17 @@ func AddMailLottery(plt string, snid int32, items []*model.ItemInfo) { ShowId: model.HallAll, }) } + +func AddMailTelCode(plt string, snid int32, code string) { + title := i18n.Tr("languages", "TelCodeTitle") + content := code + + AddMail(&AddMailParam{ + Platform: plt, + Tp: model.MSGTYPE_TelCode, + SnId: snid, + Title: title, + Content: content, + ShowId: model.HallTienlen, + }) +} diff --git a/worldsrv/shopmgr.go b/worldsrv/shopmgr.go index 293d92b..20e1c8e 100644 --- a/worldsrv/shopmgr.go +++ b/worldsrv/shopmgr.go @@ -1009,6 +1009,30 @@ func (this *ShopMgr) Exchange(param *ExchangeParam) { } } } + // 加道具 + if as.GetItems() != nil { + var itemInfo []*model.Item + for _, v := range as.GetItems() { + itemInfo = append(itemInfo, &model.Item{ + ItemId: v.GetItemId(), + ItemNum: v.GetItemNum(), + }) + } + BagMgrSingleton.AddItemsOffline(&model.AddItemParam{ + Platform: param.Platform, + SnId: param.SnId, + Change: itemInfo, + GainWay: common.GainWay_Exchange, + Operator: "system", + Remark: "兑换获得", + }, nil) + } + + // 发手机兑换码 + if as.GetTelCode() != "" { + AddMailTelCode(param.Platform, param.SnId, as.GetTelCode()) + } + ret = shop.OpResultCode_OPRC_Sucess } else { if as.GetReturnCPO() != nil { From 1db15bd6f3cfdbed00548c2dd98c0226b3740476 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 11:54:38 +0800 Subject: [PATCH 09/23] no message --- worldsrv/shopmgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldsrv/shopmgr.go b/worldsrv/shopmgr.go index 20e1c8e..a46f850 100644 --- a/worldsrv/shopmgr.go +++ b/worldsrv/shopmgr.go @@ -973,6 +973,7 @@ func (this *ShopMgr) Exchange(param *ExchangeParam) { param.CallBackFunc(shop.OpResultCode_OPRC_Error) return } + logger.Logger.Tracef("API_CreateExchange: %v", as) //dbShop var ret shop.OpResultCode if as.Tag == webapi_proto.TagCode_SUCCESS { @@ -1049,7 +1050,6 @@ func (this *ShopMgr) Exchange(param *ExchangeParam) { ret = shop.OpResultCode_OPRC_ExchangeSoldOut } } - logger.Logger.Trace("API_CreateExchange: ", as.Tag, as.GetReturnCPO()) if len(itemInfo) > 0 { BagMgrSingleton.AddItemsOffline(&model.AddItemParam{ Platform: param.Platform, From 10ce982a14f806635aa2fbb1b208c97c899d1f9d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 14:26:31 +0800 Subject: [PATCH 10/23] =?UTF-8?q?tienlen=E6=88=BF=E5=8D=A1=E5=9C=BA?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E4=B8=AD=E9=80=94=E7=A6=BB=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/tienlen/scenepolicy_tienlen.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gamesrv/tienlen/scenepolicy_tienlen.go b/gamesrv/tienlen/scenepolicy_tienlen.go index 1fe9897..7283010 100644 --- a/gamesrv/tienlen/scenepolicy_tienlen.go +++ b/gamesrv/tienlen/scenepolicy_tienlen.go @@ -591,6 +591,9 @@ func (this *SceneBaseStateTienLen) CanChangeTo(s base.SceneState) bool { // 当前状态能否换桌 func (this *SceneBaseStateTienLen) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s.IsCustom() && s.GetNumOfGames() > 0 { + return false + } return !p.IsGameing() || s.GetDestroyed() || !s.GetGaming() } From f98949201942fa15e53a71adcc08914837f55358 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 15:07:51 +0800 Subject: [PATCH 11/23] =?UTF-8?q?tienlen=E6=88=BF=E5=8D=A1=E5=9C=BA?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E4=B8=AD=E9=80=94=E7=A6=BB=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/tienlen/scenepolicy_tienlen.go | 6 ++++-- worldsrv/addmail.go | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gamesrv/tienlen/scenepolicy_tienlen.go b/gamesrv/tienlen/scenepolicy_tienlen.go index 7283010..5a249ae 100644 --- a/gamesrv/tienlen/scenepolicy_tienlen.go +++ b/gamesrv/tienlen/scenepolicy_tienlen.go @@ -591,8 +591,10 @@ func (this *SceneBaseStateTienLen) CanChangeTo(s base.SceneState) bool { // 当前状态能否换桌 func (this *SceneBaseStateTienLen) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { - if s.IsCustom() && s.GetNumOfGames() > 0 { - return false + if s.IsCustom() { + if s.NumOfGames > 0 && s.NumOfGames < int(s.TotalOfGames) { + return false + } } return !p.IsGameing() || s.GetDestroyed() || !s.GetGaming() } diff --git a/worldsrv/addmail.go b/worldsrv/addmail.go index 379b81d..dc48d36 100644 --- a/worldsrv/addmail.go +++ b/worldsrv/addmail.go @@ -41,6 +41,10 @@ func AddMail(param *AddMailParam) { return } + if param.SrcName == "" { + param.SrcName = "{\"zh\":\"系统\",\"vi\":\"GM\",\"en\":\"GM\",\"kh\":\"GM\"}" + } + opener := int32(1) if param.SrcId <= 0 { opener = 0 From 3bcc94441797725cf7370476d0fa39443c30137b Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 15:09:38 +0800 Subject: [PATCH 12/23] =?UTF-8?q?tienlen=E6=88=BF=E5=8D=A1=E5=9C=BA?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E4=B8=AD=E9=80=94=E7=A6=BB=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/base/player.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamesrv/base/player.go b/gamesrv/base/player.go index d6b6113..5aea1b3 100644 --- a/gamesrv/base/player.go +++ b/gamesrv/base/player.go @@ -216,7 +216,7 @@ func (this *Player) IsAuto() bool { } func (this *Player) IsGameing() bool { - return !this.IsMarkFlag(PlayerState_WaitNext) && !this.IsMarkFlag(PlayerState_GameBreak) && !this.IsMarkFlag(PlayerState_Bankruptcy) && !this.IsMarkFlag(PlayerState_Audience) + return !this.IsMarkFlag(PlayerState_WaitNext) && !this.IsMarkFlag(PlayerState_GameBreak) && !this.IsMarkFlag(PlayerState_Audience) } func (this *Player) IsAllFollow() bool { From dfe093b03e1172a90b0cc6e926597d990f4efd22 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 15:23:40 +0800 Subject: [PATCH 13/23] no message --- worldsrv/loginstatemgr.go | 9 ++++++--- worldsrv/player.go | 29 +++++++++++++++++++++-------- worldsrv/scene.go | 7 +++++++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/worldsrv/loginstatemgr.go b/worldsrv/loginstatemgr.go index 4c52f6e..ab7b54f 100644 --- a/worldsrv/loginstatemgr.go +++ b/worldsrv/loginstatemgr.go @@ -2,15 +2,17 @@ package main import ( "fmt" - "mongo.games.com/goserver/core/logger" "time" - "mongo.games.com/game/common" - "mongo.games.com/game/model" "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/task" + + "mongo.games.com/game/common" + "mongo.games.com/game/model" + "mongo.games.com/game/worldsrv/internal" ) const ( @@ -236,6 +238,7 @@ func (this *LoginStateMgr) LogoutAllBySession(session *netlib.Session) { p := PlayerMgrSington.GetOnlinePlayer(sid) if p != nil { p.DropLine() + internal.FirePlayerDropLine[*Player, *Scene](p) } } } diff --git a/worldsrv/player.go b/worldsrv/player.go index 7a46470..d71d73d 100644 --- a/worldsrv/player.go +++ b/worldsrv/player.go @@ -86,6 +86,7 @@ type Player struct { changeIconTime time.Time //上次修改头像时间 enterts time.Time //进入时间 lastChangeScene time.Time //上次换桌时间 + dropTime time.Time // 掉线时间 isAudience bool //是否是观众 customerToken string //客服会话token isDelete bool //是否已删档用户 @@ -1155,6 +1156,7 @@ func (this *Player) Kick(reason int32) { LoginStateMgrSington.LogoutBySid(this.sid) this.DropLine() + internal.FirePlayerDropLine[*Player, *Scene](this) } TournamentMgr.ForceQuit(this.Platform, this.SnId) } @@ -1632,10 +1634,19 @@ func (this *Player) OnSecTimer() { } func (this *Player) OnMiniTimer() { - TaskSubjectSingleton.Touch(common.TaskTypeOnlineTs, &TaskData{ - SnId: this.SnId, - Num: 60, - }) + if this.IsOnLine() { + TaskSubjectSingleton.Touch(common.TaskTypeOnlineTs, &TaskData{ + SnId: this.SnId, + Num: 60, + }) + } + // 长时间掉线又没有删除缓存 + if !this.dropTime.IsZero() && time.Now().Sub(this.dropTime).Minutes() > 20 { + logger.Logger.Errorf("清除缓存异常玩家 snid:%v dirty:%v lastLogoutTime:%v lastGameId:%v", this.SnId, this.dirty, this.LastLogoutTime, this.LastGameId) + if this.scene != nil { + logger.Logger.Errorf("清除缓存异常玩家 sceneId:%v", this.scene.sceneId) + } + } } func (this *Player) OnHourTimer() { @@ -3884,10 +3895,12 @@ func (this *Player) SCDataConfig(tp int) { func init() { internal.RegisterPlayerListenerFunc(&internal.PlayerListenerFunc[*Player, *Scene]{ - ClockFunc: common.ClockFunc{}, - OnPlayerLoginedFunc: nil, - OnPlayerLogoutedFunc: nil, - OnPlayerDropLineFunc: nil, + ClockFunc: common.ClockFunc{}, + OnPlayerLoginedFunc: nil, + OnPlayerLogoutedFunc: nil, + OnPlayerDropLineFunc: func(p *Player) { + p.dropTime = time.Now() + }, OnPlayerReholdFunc: nil, OnPlayerEnterSceneBeforeFunc: nil, OnPlayerEnterSceneAfterFunc: nil, diff --git a/worldsrv/scene.go b/worldsrv/scene.go index 3331464..d28a99b 100644 --- a/worldsrv/scene.go +++ b/worldsrv/scene.go @@ -21,6 +21,7 @@ import ( serverproto "mongo.games.com/game/protocol/server" webapiproto "mongo.games.com/game/protocol/webapi" "mongo.games.com/game/srvdata" + "mongo.games.com/game/worldsrv/internal" ) type PlayerGameCtx struct { @@ -193,6 +194,9 @@ func (this *Scene) PlayerEnter(p *Player, pos int, ischangeroom bool) bool { } } + internal.FirePlayerEnterSceneBefore(p, this) + defer internal.FirePlayerEnterSceneAfter(p, this) + // 非百人,设置座位 if !this.IsHundredScene() { if pos != -1 { @@ -515,6 +519,9 @@ func (this *Scene) lastScene(p *Player) { } func (this *Scene) DelPlayer(p *Player) bool { + internal.FirePlayerLeaveSceneBefore(p, this) + defer internal.FirePlayerLeaveSceneAfter(p, this) + if p.scene != this { roomId := 0 if p.scene != nil { From 0585fe236d41b027ca8d9162cd5597be89bb776d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Sun, 17 Nov 2024 15:20:35 +0800 Subject: [PATCH 14/23] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=87=BA?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/player.go | 1 - 1 file changed, 1 deletion(-) diff --git a/worldsrv/player.go b/worldsrv/player.go index eb8db7c..7a46470 100644 --- a/worldsrv/player.go +++ b/worldsrv/player.go @@ -1124,7 +1124,6 @@ func (this *Player) IsOnLine() bool { func (this *Player) SetOnline() { this.state = PlayerStateOnline - this.UpdateLastLogoutTime() } func (this *Player) IsOffline() bool { From d0072d40b4c2ce084acd541b5e0cbaa052ad447f Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 14 Nov 2024 17:39:35 +0800 Subject: [PATCH 15/23] =?UTF-8?q?=E6=8A=BD=E5=A5=96=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E6=88=BF=E5=8D=A1=E6=B6=88=E8=80=97=E7=BB=9F=E8=AE=A1=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/scenepolicydata.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldsrv/scenepolicydata.go b/worldsrv/scenepolicydata.go index 3feba77..cf56e8a 100644 --- a/worldsrv/scenepolicydata.go +++ b/worldsrv/scenepolicydata.go @@ -176,7 +176,9 @@ func (spd *ScenePolicyData) CostPayment(s *Scene, snid int32) bool { GameFreeId: int64(s.dbGameFree.GetId()), RoomConfigId: roomConfig.GetId(), }) - LotteryMgrInst.AddCostRoomCard(p.Platform, p.SnId, int64(n)) + if s.CustomParam.GetCostType() == 1 { // AA 是在游戏开始后扣的 + LotteryMgrInst.AddCostRoomCard(p.Platform, p.SnId, int64(n)) + } }) } From b497bd103a91e0bd4d8436b8edf52a28052021f8 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 15 Nov 2024 11:18:28 +0800 Subject: [PATCH 16/23] =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/action_player.go | 20 +++++++------------- worldsrv/player.go | 7 +------ worldsrv/playermgr.go | 1 - 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/worldsrv/action_player.go b/worldsrv/action_player.go index 0bf4180..0ba0eed 100644 --- a/worldsrv/action_player.go +++ b/worldsrv/action_player.go @@ -3173,20 +3173,14 @@ func CSUpdateAttribute(s *netlib.Session, packetId int, data interface{}, sid in return nil } if msg.GuideId == common.GuideIdNewPlayer { - if p.GuideStep >= 0 && p.GuideStep < model.GameParamData.GuideStepMaxNum { - p.GuideStep = -1 // 跳过引导为 -1 - pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess - send() - return nil - } - } else { - pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess - if len(msg.Param) > 0 { - p.GuideData[msg.GuideId] = int32(msg.Param[0]) - } - send() - return nil + p.GuideStep = -1 // 跳过引导为 -1 } + pack.OpRetCode = player_proto.OpResultCode_OPRC_Sucess + if len(msg.Param) > 0 { + p.GuideData[msg.GuideId] = int32(msg.Param[0]) + } + send() + return nil case common.AttributeGuideTest: if !common.Config.IsDevMode { return nil diff --git a/worldsrv/player.go b/worldsrv/player.go index d71d73d..8f7cfb3 100644 --- a/worldsrv/player.go +++ b/worldsrv/player.go @@ -1367,12 +1367,7 @@ func (this *Player) Time2Save() { return } - isForce := false - if common.Config.IsDevMode { - isForce = true // 开发模式下强制保存 - } - - PlayerMgrSington.SavePlayer(this, true, isForce) + PlayerMgrSington.SavePlayer(this, true, false) if this.isDelete || (!this.IsOnLine() && !this.dirty && time.Now().Sub(this.lastSaved) > time.Minute*5 && this.scene == nil) { PlayerMgrSington.DelPlayer(this.SnId) diff --git a/worldsrv/playermgr.go b/worldsrv/playermgr.go index ca941ee..456239d 100644 --- a/worldsrv/playermgr.go +++ b/worldsrv/playermgr.go @@ -173,7 +173,6 @@ func (this *PlayerMgr) SavePlayer(p *Player, isCopy, force bool) { t1 := time.Now() - p.dirty = true // 跨天任务依赖LastLogoutTime的准确性,跨天任务是定时器common.ClockMgrSington触发的,所以这里要用定时器的触发时间 p.LastLogoutTime = common.ClockMgrSingleton.LastTickTime pd.LastLogoutTime = common.ClockMgrSingleton.LastTickTime From b52f84d1829ce2654b6b8e70453a9d477fbfe7d3 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 15 Nov 2024 15:21:01 +0800 Subject: [PATCH 17/23] statistics --- go.mod | 9 +- go.sum | 19 + mongo/export.go | 11 +- mysql/export.go | 48 +++ mysql/internal/mysql.go | 150 +++++++ statistics/.gitignore | 27 ++ statistics/README.md | 8 + statistics/build_linux.bat | 8 + statistics/constant/constant.go | 13 + statistics/etc/config.yaml | 27 ++ statistics/etc/mongo.yaml | 53 +++ statistics/etc/mysql.yaml | 31 ++ statistics/local_test.go | 53 +++ statistics/logger.xml | 22 ++ statistics/main.go | 239 +++++++++++ .../mongo/model/log_gameplayerlistlog.go | 47 +++ statistics/mongo/model/log_invitescore.go | 19 + statistics/mongo/model/log_item.go | 27 ++ statistics/mongo/model/log_login.go | 33 ++ statistics/mongo/model/user_account.go | 24 ++ statistics/mysql/model/init.go | 17 + statistics/mysql/model/log_invitescore.go | 26 ++ statistics/mysql/model/log_itemgain.go | 16 + statistics/mysql/model/log_login.go | 26 ++ statistics/mysql/model/log_login_mid.go | 6 + statistics/mysql/model/log_mid.go | 11 + statistics/mysql/model/user_account.go | 18 + statistics/mysql/model/user_id.go | 9 + statistics/mysql/model/user_login.go | 29 ++ statistics/shell/close.sh | 4 + statistics/shell/start.sh | 2 + statistics/static/init.go | 1 + statistics/static/user_login.go | 372 ++++++++++++++++++ statistics/syn/init.go | 102 +++++ statistics/syn/log_invitescore.go | 291 ++++++++++++++ statistics/syn/log_itemgain.go | 61 +++ statistics/syn/log_login.go | 182 +++++++++ statistics/syn/user_account.go | 106 +++++ statistics/tools/logrus_hook.go | 95 +++++ statistics/tools/panic.go | 37 ++ util/viper.go | 29 ++ worldsrv/action_lottery.go | 9 +- 42 files changed, 2309 insertions(+), 8 deletions(-) create mode 100644 mysql/export.go create mode 100644 mysql/internal/mysql.go create mode 100644 statistics/.gitignore create mode 100644 statistics/README.md create mode 100644 statistics/build_linux.bat create mode 100644 statistics/constant/constant.go create mode 100644 statistics/etc/config.yaml create mode 100644 statistics/etc/mongo.yaml create mode 100644 statistics/etc/mysql.yaml create mode 100644 statistics/local_test.go create mode 100644 statistics/logger.xml create mode 100644 statistics/main.go create mode 100644 statistics/mongo/model/log_gameplayerlistlog.go create mode 100644 statistics/mongo/model/log_invitescore.go create mode 100644 statistics/mongo/model/log_item.go create mode 100644 statistics/mongo/model/log_login.go create mode 100644 statistics/mongo/model/user_account.go create mode 100644 statistics/mysql/model/init.go create mode 100644 statistics/mysql/model/log_invitescore.go create mode 100644 statistics/mysql/model/log_itemgain.go create mode 100644 statistics/mysql/model/log_login.go create mode 100644 statistics/mysql/model/log_login_mid.go create mode 100644 statistics/mysql/model/log_mid.go create mode 100644 statistics/mysql/model/user_account.go create mode 100644 statistics/mysql/model/user_id.go create mode 100644 statistics/mysql/model/user_login.go create mode 100644 statistics/shell/close.sh create mode 100644 statistics/shell/start.sh create mode 100644 statistics/static/init.go create mode 100644 statistics/static/user_login.go create mode 100644 statistics/syn/init.go create mode 100644 statistics/syn/log_invitescore.go create mode 100644 statistics/syn/log_itemgain.go create mode 100644 statistics/syn/log_login.go create mode 100644 statistics/syn/user_account.go create mode 100644 statistics/tools/logrus_hook.go create mode 100644 statistics/tools/panic.go create mode 100644 util/viper.go diff --git a/go.mod b/go.mod index 94ea1fb..70fd5d8 100644 --- a/go.mod +++ b/go.mod @@ -18,8 +18,10 @@ require ( github.com/howeyc/fsnotify v0.9.0 github.com/idealeak/goserver v0.0.0-20201014040547-b8f686262078 github.com/jinzhu/now v1.1.5 + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/mojocn/base64Captcha v1.3.6 + github.com/sirupsen/logrus v1.9.0 github.com/spf13/cast v1.7.0 github.com/spf13/viper v1.19.0 github.com/tealeg/xlsx v1.0.5 @@ -33,10 +35,13 @@ require ( golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 + gorm.io/driver/mysql v1.5.7 + gorm.io/gorm v1.25.12 mongo.games.com/goserver v0.0.0-00010101000000-000000000000 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1 // indirect github.com/containrrr/shoutrrr v0.6.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect @@ -45,6 +50,7 @@ require ( github.com/dlclark/regexp2 v1.10.0 // indirect github.com/fatih/color v1.17.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gocarina/gocsv v0.0.0-20221105105431-c8ef78125b99 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -53,9 +59,11 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/innopals/sls-logrus-hook v0.0.0-20190808032145-2fe1d6f7ce00 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/klauspost/reedsolomon v1.12.4 // indirect + github.com/lestrrat-go/strftime v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -68,7 +76,6 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect diff --git a/go.sum b/go.sum index 0bc191c..ab41286 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1 h1:j56fC19WoD3z+u+ZHxm2XwRGyS1XmdSMk7058BLhdsM= github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1/go.mod h1:gXEhMjm1VadSGjAzyDlBxmdYglP8eJpYWxpwJnmXRWw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -92,6 +94,9 @@ github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gocarina/gocsv v0.0.0-20221105105431-c8ef78125b99 h1:qNAaZUnCulf2xIQc7rM6F3uGYr80h40rtilsVKyAHoM= github.com/gocarina/gocsv v0.0.0-20221105105431-c8ef78125b99/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= @@ -159,8 +164,11 @@ github.com/innopals/sls-logrus-hook v0.0.0-20190808032145-2fe1d6f7ce00 h1:QfdUfo github.com/innopals/sls-logrus-hook v0.0.0-20190808032145-2fe1d6f7ce00/go.mod h1:Q24O6QMGImDU3WY71P4YAxNb36NNn5qaznCfMUoXVfc= github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -186,6 +194,12 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg= +github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -581,6 +595,11 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= diff --git a/mongo/export.go b/mongo/export.go index aeac899..a86a949 100644 --- a/mongo/export.go +++ b/mongo/export.go @@ -25,17 +25,18 @@ type Collection = internal.Collection type Database = internal.Database var _manager *internal.Manager -var _conf *internal.Config // GetConfig 获取配置 func GetConfig() *Config { - return _conf + if _manager == nil { + return nil + } + return _manager.GetConfig() } // Init 初始化 func Init(conf *Config) { - _conf = conf - _manager = internal.NewManager(_conf) + _manager = internal.NewManager(conf) } // Restart 重启 @@ -44,7 +45,7 @@ func Restart() { logger.Logger.Error(NotInitError) return } - _manager.Restart(_conf) + _manager.Restart(_manager.GetConfig()) } // Close 关闭 diff --git a/mysql/export.go b/mysql/export.go new file mode 100644 index 0000000..229bcaf --- /dev/null +++ b/mysql/export.go @@ -0,0 +1,48 @@ +package mysql + +import ( + "errors" + + "mongo.games.com/game/mysql/internal" +) + +var NotInitError = errors.New("mysql manager is nil, please call Init() first") + +type Config = internal.Config +type DatabaseConfig = internal.DatabaseConfig +type Database = internal.Database + +var manager *internal.Manager + +func Init(conf *Config) error { + manager = internal.NewManager(conf) + return nil +} + +func SetAutoMigrateTables(tables []interface{}) { + if manager == nil { + return + } + manager.SetAutoMigrateTables(tables) +} + +func GetConfig() *Config { + if manager == nil { + return nil + } + return manager.GetConfig() +} + +func Close() { + if manager == nil { + return + } + manager.Close() +} + +func GetDatabase(platform string) (*Database, error) { + if manager == nil { + return nil, NotInitError + } + return manager.GetDatabase(platform) +} diff --git a/mysql/internal/mysql.go b/mysql/internal/mysql.go new file mode 100644 index 0000000..5aa82b5 --- /dev/null +++ b/mysql/internal/mysql.go @@ -0,0 +1,150 @@ +package internal + +import ( + "fmt" + "sync" + "time" + + "gorm.io/driver/mysql" + "gorm.io/gorm" + "mongo.games.com/goserver/core/logger" +) + +type Config struct { + Platforms map[string]*DatabaseConfig + MaxIdleConns int + MaxOpenConns int + ConnMaxLifetime int + ConnMaxIdletime int +} + +type DatabaseConfig struct { + HostName string + HostPort int32 + Database string + Username string + Password string + Options string +} + +type Database struct { + *Manager + *Config + *DatabaseConfig + *gorm.DB +} + +func (d *Database) Connect() error { + if d.DatabaseConfig == nil { + err := fmt.Errorf("mysql Connect error, DatabaseConifg not found") + logger.Logger.Error(err) + return err + } + + login := "" + if d.DatabaseConfig.Username != "" { + login = d.DatabaseConfig.Username + ":" + d.DatabaseConfig.Password + "@" + } + host := d.DatabaseConfig.HostName + if d.DatabaseConfig.HostName == "" { + host = "127.0.0.1" + } + port := d.DatabaseConfig.HostPort + if d.DatabaseConfig.HostPort == 0 { + port = 3306 + } + database := d.DatabaseConfig.Database + if database == "" { + database = "mysql" + } + myOptions := d.DatabaseConfig.Options + if myOptions != "" { + myOptions = "?" + myOptions + } + + // [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] + s := fmt.Sprintf("%stcp(%s:%d)/%s%s", login, host, port, "mysql", myOptions) + db, err := gorm.Open(mysql.Open(s), &gorm.Config{}) + if err != nil { + logger.Logger.Errorf("mysql Connect %v error: %v config:%+v", s, err, *d.DatabaseConfig) + return err + } + logger.Logger.Tracef("mysql connect success %+v", *d.DatabaseConfig) + + err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", d.DatabaseConfig.Database)).Error + if err != nil { + logger.Logger.Errorf("mysql create database %s error: %v", d.DatabaseConfig.Database, err) + return err + } + + s = fmt.Sprintf("%stcp(%s:%d)/%s%s", login, host, port, d.DatabaseConfig.Database, myOptions) + db, err = gorm.Open(mysql.Open(s), &gorm.Config{SkipDefaultTransaction: true}) + if err != nil { + logger.Logger.Errorf("mysql Connect %v error: %v config:%+v", s, err, *d.DatabaseConfig) + return err + } + + sqlDB, err := db.DB() + if err != nil { + logger.Logger.Errorf("mysql get DB error: %v", err) + return err + } + + if len(d.tables) > 0 { + if err := db.AutoMigrate(d.tables...); err != nil { + logger.Logger.Warnf("mysql migrate error: %v", err) + } + } + + sqlDB.SetMaxIdleConns(d.MaxIdleConns) + sqlDB.SetMaxOpenConns(d.MaxOpenConns) + sqlDB.SetConnMaxLifetime(time.Duration(d.ConnMaxLifetime)) + sqlDB.SetConnMaxIdleTime(time.Duration(d.ConnMaxIdletime)) + + d.DB = db.Session(&gorm.Session{SkipDefaultTransaction: true}) + + return nil +} + +type Manager struct { + conf *Config + platforms sync.Map // 平台id:Database + tables []interface{} +} + +func (m *Manager) GetConfig() *Config { + return m.conf +} + +func (m *Manager) SetAutoMigrateTables(tables []interface{}) { + m.tables = tables +} + +func (m *Manager) GetDatabase(key string) (*Database, error) { + v, ok := m.platforms.Load(key) // 平台id + if !ok { + db := &Database{ + Manager: m, + Config: m.conf, + DatabaseConfig: m.conf.Platforms[key], + } + if err := db.Connect(); err != nil { + return nil, err + } + v = db + m.platforms.Store(key, v) + } + d, _ := v.(*Database) + return d, nil +} + +func (m *Manager) Close() { + +} + +func NewManager(conf *Config) *Manager { + return &Manager{ + conf: conf, + platforms: sync.Map{}, + } +} diff --git a/statistics/.gitignore b/statistics/.gitignore new file mode 100644 index 0000000..43aacb1 --- /dev/null +++ b/statistics/.gitignore @@ -0,0 +1,27 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +.idea +.vscode +log + diff --git a/statistics/README.md b/statistics/README.md new file mode 100644 index 0000000..88cdc2b --- /dev/null +++ b/statistics/README.md @@ -0,0 +1,8 @@ +# statistics + +数据分析服务 + + * 定时查询注册表和登录日志获取玩家id,根据玩家id触发相关的数据统计 + +- [x] 新手离开记录 +- [ ] 在线时长 \ No newline at end of file diff --git a/statistics/build_linux.bat b/statistics/build_linux.bat new file mode 100644 index 0000000..7962122 --- /dev/null +++ b/statistics/build_linux.bat @@ -0,0 +1,8 @@ +set GOPATH=D:\godev +go env -w GO111MODULE=on + +set CGO_ENABLED=0 +set GOOS=linux +set GOARCH=amd64 +go build +pause \ No newline at end of file diff --git a/statistics/constant/constant.go b/statistics/constant/constant.go new file mode 100644 index 0000000..bf3f798 --- /dev/null +++ b/statistics/constant/constant.go @@ -0,0 +1,13 @@ +package constant + +const ( + User = "user" // 用户库内部名称 + Log = "log" // 日志库内部名称 +) + +const ( + InviteScoreTypeBind = 1 // 绑定邀请码 + InviteScoreTypePay = 2 // 充值返佣 + InviteScoreTypeRecharge = 3 // 充值完成 + InviteScoreTypePayMe = 4 // 充值(自己) +) diff --git a/statistics/etc/config.yaml b/statistics/etc/config.yaml new file mode 100644 index 0000000..ba82d5c --- /dev/null +++ b/statistics/etc/config.yaml @@ -0,0 +1,27 @@ +# 平台id +platforms: + - 1 + +# 几秒同步一次数据 +# 注册表,登录日志表 +update_second: 60 +# 注册表每次同步多少条数据 +update_account_num: 100 +# 登录日志每次同步多少条数据 +update_login_num: 100 +# 几秒读取一次玩家id列表 +update_second_snid: 30 +# 最多触发几个玩家数据更新 +update_snid_num: 100 + +# 邀请数据统计 +# 几秒读取一次邀请记录 +update_second_invite: 10 +# 一次最多读取多少条邀请记录 +update_invite_num: 30 + +# 道具获得数量统计 +# 几秒读取一次道具日志 +update_second_item: 10 +# 一次最多读取多少道具日志 +update_item_num: 100 \ No newline at end of file diff --git a/statistics/etc/mongo.yaml b/statistics/etc/mongo.yaml new file mode 100644 index 0000000..7f9e42d --- /dev/null +++ b/statistics/etc/mongo.yaml @@ -0,0 +1,53 @@ +global: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_global + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log + Username: + Password: + Options: + monitor: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_monitor + Username: + Password: + Options: +platforms: + 0: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_user_plt_000 + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log_plt_000 + Username: + Password: + Options: + 1: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_user_plt_001 + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log_plt_001 + Username: + Password: + Options: \ No newline at end of file diff --git a/statistics/etc/mysql.yaml b/statistics/etc/mysql.yaml new file mode 100644 index 0000000..b639fbf --- /dev/null +++ b/statistics/etc/mysql.yaml @@ -0,0 +1,31 @@ +platforms: + global: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_user + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + 0: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_plt_000 + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + 1: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_plt_001 + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + +# 最大空闲连接数 +MaxIdleConns: 10 +# 最大连接数 +MaxOpenConns: 100 +# 连接可复用的最大时间 +ConnMaxLifetime: 3600 +# 连接最大空闲时间 +ConnMaxIdletime: 0 \ No newline at end of file diff --git a/statistics/local_test.go b/statistics/local_test.go new file mode 100644 index 0000000..9e66fc5 --- /dev/null +++ b/statistics/local_test.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "fmt" + "testing" + "time" +) + +type A struct { +} + +func B() *A { + return nil +} + +func Test1(t *testing.T) { + var a interface{} + a = B() + fmt.Println(a == nil) // false +} + +func Test2(t *testing.T) { + c1 := context.Background() + c2, cancel2 := context.WithCancel(c1) + c3, _ := context.WithCancel(c2) + + go func() { + select { + case <-c3.Done(): + fmt.Println("c3 cancel") + } + }() + + time.Sleep(time.Second * 5) + cancel2() + fmt.Println("cancel2") + + //time.Sleep(time.Second * 5) + //cancel3() + //fmt.Println("cancel3") + + time.Sleep(time.Minute) +} + +func Test3(t *testing.T) { + n := time.Now() + y, m, d := n.Date() + n = time.Date(y, m, d, 0, 0, 0, 0, time.Local) + st := n.AddDate(0, 0, -int(n.Weekday())) + et := n.AddDate(0, 0, 7-int(n.Weekday())) + fmt.Println(st, et) +} diff --git a/statistics/logger.xml b/statistics/logger.xml new file mode 100644 index 0000000..f6eb37b --- /dev/null +++ b/statistics/logger.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/statistics/main.go b/statistics/main.go new file mode 100644 index 0000000..56d81aa --- /dev/null +++ b/statistics/main.go @@ -0,0 +1,239 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "sync" + "time" + + "github.com/spf13/viper" + "mongo.games.com/goserver/core/logger" + + "mongo.games.com/game/mongo" + "mongo.games.com/game/mysql" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" + "mongo.games.com/game/statistics/static" + "mongo.games.com/game/statistics/syn" + "mongo.games.com/game/statistics/tools" + "mongo.games.com/game/util" +) + +var VP *viper.Viper + +//func init() { +// // 日志 +// *log.StandardLogger() = *log.New() +// +// // 日志等级 +// level, err := log.ParseLevel(VP.GetString("log.level")) +// if err != nil { +// panic(err) +// } +// log.SetLevel(level) +// +// // 打印文件路径及行号 +// log.AddHook(tools.NewFileLineHook(log.ErrorLevel)) +// +// // 日志切分 +// for _, v := range VP.Get("log.rotate").([]interface{}) { +// conf := &tools.RotateLogConfig{} +// b, err := json.Marshal(v) +// if err != nil { +// panic(err) +// } +// if err = json.Unmarshal(b, conf); err != nil { +// panic(err) +// } +// log.AddHook(tools.NewRotateLogHook(conf)) +// } +//} + +// DoTick 定时执行 +func DoTick(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, fu func(ctx context.Context)) { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-ctx.Done(): + return + case <-time.After(duration): + tools.RecoverPanicFunc() // 捕获异常 + fu(ctx) + } + } + }() +} + +func DoTickPlatform(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, batchSize int, + fu func(ctx context.Context, platform string, batchSize int)) { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-ctx.Done(): + return + case <-time.After(duration): + tools.RecoverPanicFunc() // 捕获异常 + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + fu(ctx, platform, batchSize) + }() + } + wg.Wait() + } + } + }() +} + +func main() { + VP = util.GetViper("config", "yaml") + // mongo + vp := util.GetViper("mongo", "yaml") + // mongo初始化 + conf := &mongo.Config{} + err := vp.Unmarshal(conf) + if err != nil { + panic(fmt.Errorf("mongo config error: %v", err)) + } + mongo.Init(conf) + defer mongo.Close() + + // mysql + vp = util.GetViper("mysql", "yaml") + myConf := &mysql.Config{} + err = vp.Unmarshal(myConf) + if err != nil { + panic(fmt.Errorf("mysql config error: %v", err)) + } + mysql.Init(myConf) + defer mysql.Close() + + mysql.SetAutoMigrateTables(mysqlmodel.Tables) + + wg := &sync.WaitGroup{} + ctx, cancel := context.WithCancel(context.Background()) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second"))*time.Second, SyncSnId) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_snid"))*time.Second, func(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + Static(platform) + }() + } + wg.Wait() + }) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_invite"))*time.Second, SyncInvite) + + DoTickPlatform(ctx, wg, time.Duration(VP.GetInt64("update_second_item"))*time.Second, VP.GetInt("update_item_num"), + func(ctx context.Context, platform string, batchSize int) { + err := syn.ItemGainDone(&syn.Data[mongomodel.ItemLog]{ + Platform: platform, + BatchSize: batchSize, + }) + if err != nil { + logger.Logger.Errorf("SyncItem error:%v", err) + } + }) + + logger.Logger.Info("start") + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, os.Kill) + sig := <-c + logger.Logger.Infof("closing down (signal: %v)", sig) + + // release + cancel() + wg.Wait() + + logger.Logger.Info("closed") +} + +// SyncSnId 同步注册和登录日志 +func SyncSnId(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + _, err := syn.UserAccount(platform, VP.GetInt("update_account_num")) + if err != nil { + logger.Logger.Errorf("SyncUserAccount error: %v", err) + return + } + + _, err = syn.LogLogin(platform, VP.GetInt("update_login_num")) + if err != nil { + logger.Logger.Errorf("SyncLogLogin error: %v", err) + return + } + }() + } + wg.Wait() +} + +// Static 玩家id触发数据统计 +func Static(platform string) { + // 查询需要更新的玩家id + var ids []*mysqlmodel.UserID + db, err := mysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("GetDatabase error: %v", err) + return + } + if err := db.Limit(VP.GetInt("update_snid_num")).Find(&ids).Error; err != nil { + logger.Logger.Warnf("Get UserID error: %v", err) + return + } + + if len(ids) == 0 { + logger.Logger.Tracef("Static: no need to update") + return + } + + // 统计玩家跳出记录 + if err := static.UserLogin(platform, ids); err != nil { + logger.Logger.Errorf("StaticUserLogin error: %v", err) + return + } + + // 删除更新过的玩家id + if err := db.Delete(ids).Error; err != nil { + logger.Logger.Errorf("Delete error: %v", err) + return + } +} + +// SyncInvite 同步邀请数据 +func SyncInvite(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + err := syn.SyncInviteScore(platform, VP.GetInt("update_invite_num")) + if err != nil { + logger.Logger.Errorf("SyncInviteScore error: %v", err) + return + } + }() + } + wg.Wait() +} diff --git a/statistics/mongo/model/log_gameplayerlistlog.go b/statistics/mongo/model/log_gameplayerlistlog.go new file mode 100644 index 0000000..4eeac20 --- /dev/null +++ b/statistics/mongo/model/log_gameplayerlistlog.go @@ -0,0 +1,47 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogGamePlayerListLog = "log_gameplayerlistlog" + +type GamePlayerListLog struct { + LogId primitive.ObjectID `bson:"_id"` + SnId int32 //用户Id + Name string //名称 + GameId int32 //游戏id + BaseScore int32 //游戏底注 + ClubId int32 //俱乐部Id + ClubRoom string //俱乐部包间 + TaxCoin int64 //税收 + ClubPumpCoin int64 //俱乐部额外抽水 + Platform string //平台id + Channel string //渠道 + Promoter string //推广员 + PackageTag string //包标识 + SceneId int32 //场景ID + GameMode int32 //游戏类型 + GameFreeid int32 //游戏类型房间号 + GameDetailedLogId string //游戏记录Id + IsFirstGame bool //是否第一次游戏 + //对于拉霸类:BetAmount=100 WinAmountNoAnyTax=0 (表示投入多少、收益多少,值>=0) + //拉霸类小游戏会是:BetAmount=0 WinAmountNoAnyTax=100 (投入0、收益多少,值>=0) + //对战场:BetAmount=0 WinAmountNoAnyTax=100 (投入会有是0、收益有正负,WinAmountNoAnyTax=100则盈利,WinAmountNoAnyTax=-100则输100) + BetAmount int64 //下注金额 + WinAmountNoAnyTax int64 //盈利金额,不包含任何税 + TotalIn int64 //本局投入 + TotalOut int64 //本局产出 + Time time.Time //记录时间 + RoomType int32 //房间类型 + GameDif string //游戏标识 + GameClass int32 //游戏类型 1棋牌 2电子 3百人 4捕鱼 5视讯 6彩票 7体育 + MatchId int32 + MatchType int32 //0.普通场 1.锦标赛 2.冠军赛 3.vip专属 + Ts int32 + IsFree bool //拉霸专用 是否免费 + WinSmallGame int64 //拉霸专用 小游戏奖励 + WinTotal int64 //拉霸专用 输赢 +} diff --git a/statistics/mongo/model/log_invitescore.go b/statistics/mongo/model/log_invitescore.go new file mode 100644 index 0000000..4e6253c --- /dev/null +++ b/statistics/mongo/model/log_invitescore.go @@ -0,0 +1,19 @@ +package model + +import ( + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogInviteScore = "log_invitescore" + +type InviteScore struct { + Id primitive.ObjectID `bson:"_id"` + UpSnid int // 上级代理 + DownSnid int // 下级代理 + Level int // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Tp int // 返佣类型 + Rate int // 返佣比例 + Score int // 积分 + Money int // 充值金额 + Ts int // 时间戳 +} diff --git a/statistics/mongo/model/log_item.go b/statistics/mongo/model/log_item.go new file mode 100644 index 0000000..0c6bf87 --- /dev/null +++ b/statistics/mongo/model/log_item.go @@ -0,0 +1,27 @@ +package model + +import "go.mongodb.org/mongo-driver/bson/primitive" + +const LogItem = "log_itemlog" + +type ItemInfo struct { + ItemId int32 + ItemNum int64 +} + +type ItemLog struct { + LogId primitive.ObjectID `bson:"_id"` + Platform string //平台 + SnId int32 //玩家id + LogType int32 //记录类型 0.获取 1.消耗 + ItemId int32 //道具id + ItemName string //道具名称 + Count int64 //个数 + CreateTs int64 //记录时间 + Remark string //备注 + TypeId int32 // 变化类型 + GameId int32 // 游戏id,游戏中获得时有值 + GameFreeId int32 // 场次id,游戏中获得时有值 + Cost []*ItemInfo // 消耗的道具 + Id string // 撤销的id,兑换失败 +} diff --git a/statistics/mongo/model/log_login.go b/statistics/mongo/model/log_login.go new file mode 100644 index 0000000..7394d3e --- /dev/null +++ b/statistics/mongo/model/log_login.go @@ -0,0 +1,33 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogLogin = "log_login" + +const ( + LogTypeLogin int32 = iota // 登录 + LogTypeLogout // 登出 + LogTypeRehold // 重连 + LogTypeDrop // 掉线 +) + +type LoginLog struct { + LogId primitive.ObjectID `bson:"_id"` + Platform string //平台id + SnId int32 + LogType int32 + Ts int64 + Time time.Time + GameId int // 玩家掉线时所在游戏id + LastGameID int // 玩家最后所在游戏id + ChannelId string // 推广渠道 + + DeviceName string + AppVersion string + BuildVersion string + AppChannel string +} diff --git a/statistics/mongo/model/user_account.go b/statistics/mongo/model/user_account.go new file mode 100644 index 0000000..f87bc7d --- /dev/null +++ b/statistics/mongo/model/user_account.go @@ -0,0 +1,24 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const UserAccount = "user_account" + +type Account struct { + AccountId primitive.ObjectID `bson:"_id"` + SnId int32 // 玩家账号直接在这里生成 + Platform string // 平台 + RegisterTs int64 // 注册时间戳 + RegisteTime time.Time + ChannelId string // 推广渠道 + + Tel string `gorm:"index"` + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` +} diff --git a/statistics/mysql/model/init.go b/statistics/mysql/model/init.go new file mode 100644 index 0000000..976ac05 --- /dev/null +++ b/statistics/mysql/model/init.go @@ -0,0 +1,17 @@ +package model + +// 需要自动迁移的表添加在这里 Tables + +var Tables = []interface{}{ + &LogLogin{}, + &LogLoginMid{}, + &UserAccount{}, + &UserLogin{}, + &UserID{}, + &LogInviteScoreMid{}, + &LogInviteScore{}, + &LogInviteUser{}, + &LogMid{}, + &ItemGain{}, + &ItemTotalGain{}, +} diff --git a/statistics/mysql/model/log_invitescore.go b/statistics/mysql/model/log_invitescore.go new file mode 100644 index 0000000..177d219 --- /dev/null +++ b/statistics/mysql/model/log_invitescore.go @@ -0,0 +1,26 @@ +package model + +type LogInviteScoreMid struct { + ID uint `gorm:"primaryKey"` + MID string +} + +type LogInviteScore struct { + ID uint `gorm:"primaryKey"` + UpSnid int `gorm:"index"` // 上级代理 + DownSnid int `gorm:"index"` // 下级代理 + Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Tp int `gorm:"index"` // 返佣类型 + Rate int `gorm:"index"` // 返佣比例 + Score int `gorm:"index"` // 积分 + Money int `gorm:"index"` // 充值金额 + Ts int `gorm:"index"` // 时间戳 +} + +type LogInviteUser struct { + ID uint `gorm:"primaryKey"` + Psnid int `gorm:"index"` // 当前玩家 + Snid int `gorm:"index"` // 一级代理 + Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Ts int `gorm:"index"` // 绑定时间 +} diff --git a/statistics/mysql/model/log_itemgain.go b/statistics/mysql/model/log_itemgain.go new file mode 100644 index 0000000..b361104 --- /dev/null +++ b/statistics/mysql/model/log_itemgain.go @@ -0,0 +1,16 @@ +package model + +// ItemGain 道具获得数量,以小时,道具id,做主键 +type ItemGain struct { + ID uint `gorm:"primaryKey"` + Hour int64 `gorm:"index:idx_item"` // 小时时间戳,每小时统计一次 + ItemId int32 `gorm:"index:idx_item"` // 道具id + ItemNum int64 // 道具数量 +} + +// ItemTotalGain 道具获得总数 +type ItemTotalGain struct { + ID uint `gorm:"primaryKey"` + ItemId int32 `gorm:"index"` // 道具id + ItemNum int64 // 道具数量 +} diff --git a/statistics/mysql/model/log_login.go b/statistics/mysql/model/log_login.go new file mode 100644 index 0000000..3d1aea4 --- /dev/null +++ b/statistics/mysql/model/log_login.go @@ -0,0 +1,26 @@ +package model + +import "time" + +const ( + LogTypeLogin = 1 // 登录 + LogTypeRehold = 2 // 重连 + LogTypeOffline = 3 // 离线 +) + +type LogLogin struct { + ID uint `gorm:"primaryKey"` + Snid int `gorm:"index"` + OnlineType int `gorm:"index"` + //OnlineTs int `gorm:"index"` + OnlineTime time.Time `gorm:"index"` + OfflineType int `gorm:"index"` + //OfflineTs int `gorm:"index"` + OfflineTime time.Time `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 + + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` +} diff --git a/statistics/mysql/model/log_login_mid.go b/statistics/mysql/model/log_login_mid.go new file mode 100644 index 0000000..d46df2e --- /dev/null +++ b/statistics/mysql/model/log_login_mid.go @@ -0,0 +1,6 @@ +package model + +type LogLoginMid struct { + ID uint `gorm:"primaryKey"` + MID string +} diff --git a/statistics/mysql/model/log_mid.go b/statistics/mysql/model/log_mid.go new file mode 100644 index 0000000..047c56c --- /dev/null +++ b/statistics/mysql/model/log_mid.go @@ -0,0 +1,11 @@ +package model + +const ( + MidTypeItem = 1 // 道具记录 +) + +type LogMid struct { + ID uint `gorm:"primaryKey"` + Tp int `gorm:"index"` // 类型 + MID string +} diff --git a/statistics/mysql/model/user_account.go b/statistics/mysql/model/user_account.go new file mode 100644 index 0000000..d0c61d1 --- /dev/null +++ b/statistics/mysql/model/user_account.go @@ -0,0 +1,18 @@ +package model + +import "time" + +type UserAccount struct { + ID uint `gorm:"primaryKey"` + MID string + Snid int `gorm:"index"` + //RegisterTs int `gorm:"index"` + RegisterTime time.Time `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 + + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` + Tel string `gorm:"index"` +} diff --git a/statistics/mysql/model/user_id.go b/statistics/mysql/model/user_id.go new file mode 100644 index 0000000..a8c2360 --- /dev/null +++ b/statistics/mysql/model/user_id.go @@ -0,0 +1,9 @@ +package model + +/* + 服务定期查询注册和登录信息,然后获取玩家id,保存到这张表中;用于后续触发和玩家相关的数据统计 +*/ + +type UserID struct { + Snid int `gorm:"primaryKey"` +} diff --git a/statistics/mysql/model/user_login.go b/statistics/mysql/model/user_login.go new file mode 100644 index 0000000..a5235e2 --- /dev/null +++ b/statistics/mysql/model/user_login.go @@ -0,0 +1,29 @@ +package model + +import "time" + +const ( + OutTypRegister = 1 // 注册 + OutTypeLogin = 2 // 登录 + OutTypeGaming = 3 // 游戏中 + OutTypeGameOver = 4 // 游戏结束 +) + +type UserLogin struct { + ID uint `gorm:"primaryKey"` + Snid int `gorm:"uniqueIndex"` + //OnlineTs int `gorm:"index"` + OnlineTime time.Time `gorm:"index"` + //OfflineTs int `gorm:"index"` + OfflineTime time.Time `gorm:"index"` + OutType int `gorm:"index"` // 跳出类型 + GameID int `gorm:"index"` // 游戏id + Age int + Sex int + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` + Tel string `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 +} diff --git a/statistics/shell/close.sh b/statistics/shell/close.sh new file mode 100644 index 0000000..47f55d7 --- /dev/null +++ b/statistics/shell/close.sh @@ -0,0 +1,4 @@ +#!/bin/bash +pkill -2 statistics +echo "close ..." +tail -f log/all_log \ No newline at end of file diff --git a/statistics/shell/start.sh b/statistics/shell/start.sh new file mode 100644 index 0000000..980d151 --- /dev/null +++ b/statistics/shell/start.sh @@ -0,0 +1,2 @@ +#!/bin/bash +nohup ./statistics > /dev/null & diff --git a/statistics/static/init.go b/statistics/static/init.go new file mode 100644 index 0000000..4a9e036 --- /dev/null +++ b/statistics/static/init.go @@ -0,0 +1 @@ +package static diff --git a/statistics/static/user_login.go b/statistics/static/user_login.go new file mode 100644 index 0000000..ca7f8a8 --- /dev/null +++ b/statistics/static/user_login.go @@ -0,0 +1,372 @@ +package static + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "mongo.games.com/goserver/core/logger" + + mymongo "mongo.games.com/game/mongo" + mymysql "mongo.games.com/game/mysql" + + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" +) + +func getAccountTel(platform string, id int) (string, error) { + acc := &mongomodel.Account{} + cc, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.User, mongomodel.UserAccount, err) + return "", err + } + dd := cc.FindOne(context.TODO(), bson.M{"snid": id}, options.FindOne().SetProjection(bson.M{"tel": 1})) + err = dd.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("getAccountTel %v not found in user_account", id) + return "", nil + } + logger.Logger.Errorf("getAccountTel %v get user_account err: %v", id, err) + return "", err + } + if err := dd.Decode(acc); err != nil { + logger.Logger.Errorf("getAccountTel %v decode user_account err: %v", id, err) + return "", err + } + return acc.Tel, nil +} + +// 游戏结束离开 +func checkGameOver(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录并且是游戏结束离开 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": 0, "lastgameid": bson.D{{"$gt", 0}}}, + options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkGameOver %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkGameOver %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkGameOver %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeGameOver, + GameID: a.LastGameID, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 游戏中离开 +func checkGaming(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录并且是游戏中掉线 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": bson.D{{"$gt", 0}}}, + options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkGaming %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkGaming %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkGaming %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeGaming, + GameID: a.GameId, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 登录后离开 +func checkLogin(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop}, options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkLogin %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkLogin %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkLogin %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeLogin, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 注册后离开 +func checkRegister(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + a := &mongomodel.Account{} + c, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.UserAccount, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id}) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Warnf("checkRegister %v not found in user_account", id) + return false, nil + } + logger.Logger.Errorf("checkRegister %v get user_account err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkRegister %v decode user_account err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + login.Snid = id + //login.OnlineTs = int(a.RegisterTs) + login.OnlineTime = a.RegisteTime + //login.OfflineTs = int(a.RegisterTs) + login.OfflineTime = a.RegisteTime + login.OutType = mysqlmodel.OutTypRegister + login.Tel = tel + login.DeviceName = a.DeviceName + login.AppVersion = a.AppVersion + login.BuildVersion = a.BuildVersion + login.AppChannel = a.AppChannel + login.ChannelId = a.ChannelId + + if err := db.Create(login).Error; err != nil { + logger.Logger.Errorf("checkRegister create err: %v", err) + return false, err + } + return true, nil +} + +// UserLogin 玩家跳出统计 +func UserLogin(platform string, ids []*mysqlmodel.UserID) error { + f := func(id int) error { + // 玩家是否已经统计结束,已经是游戏结束状态 + login := &mysqlmodel.UserLogin{} + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("UserLogin get db err: %v", err) + return err + } + if err = db.Where("snid = ?", id).Find(login).Error; err != nil { + logger.Logger.Errorf("UserLogin find %v err: %v", id, err) + return err + } + + switch login.OutType { + case mysqlmodel.OutTypeGameOver: + return nil + + case mysqlmodel.OutTypeGaming: + _, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + return nil + + case mysqlmodel.OutTypeLogin: + ret, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + + case mysqlmodel.OutTypRegister: + ret, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkLogin(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) + return err + } + if ret { + return nil + } + + default: + ret, err := checkRegister(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkRegister %v err: %v", id, err) + return err + } + if !ret { + logger.Logger.Warnf("UserLogin not found user_account checkRegister %v err: %v", id, err) + return nil + } + + ret, err = checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkLogin(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) + return err + } + if ret { + return nil + } + return nil + } + + return nil + } + + for _, v := range ids { + if err := f(v.Snid); err != nil { + return err + } + } + + return nil +} diff --git a/statistics/syn/init.go b/statistics/syn/init.go new file mode 100644 index 0000000..b7247af --- /dev/null +++ b/statistics/syn/init.go @@ -0,0 +1,102 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mymongo "mongo.games.com/game/mongo" + mymysql "mongo.games.com/game/mysql" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" + "mongo.games.com/goserver/core/logger" +) + +// Data 数据同步方法 +// T mongodb数据表结构 +// F mongodb中的每条数据的处理操作,自行实现 +type Data[T any] struct { + Platform string // 平台 + MidType int // 数据类型 例如 model.MidTypeItem + Database string // 库名称 + CollectionName string // 集合名称 + BatchSize int // 一次读取数量 + // F 自定义数据处理方法 + // data: mongodb中的一条日志 + F func(data *T, db *gorm.DB) (string, error) +} + +// CommonDone 数据获取方式,根据mongodb集合主键按时间顺序批量读取 +func (d *Data[T]) CommonDone() error { + db, err := mymysql.GetDatabase(d.Platform) + if err != nil { + logger.Logger.Errorf("mysql: failed to get database: %v", err) + return err + } + loginMID := &mysqlmodel.LogMid{Tp: d.MidType} + var n int64 + err = db.Model(&mysqlmodel.LogMid{}).Find(loginMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: failed to get log_mid: %v", err) + return err + } + if n == 0 { + if err = db.Create(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: failed to create log_mid: %v", err) + return err + } + } + + logger.Logger.Tracef("start log_mid tp:%v _id:%v", loginMID.Tp, loginMID.MID) + + _id, _ := primitive.ObjectIDFromHex(loginMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetCollection(d.Platform, mymongo.DatabaseType(d.Database), d.CollectionName) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", d.Database, d.CollectionName, err) + return err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(d.BatchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) + return err + } + + var logs []*T + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil + } + + logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) + return err + } + l.Close(context.TODO()) + if len(logs) == 0 { + logger.Logger.Infof("sync %v finished", d.CollectionName) + return nil + } + + err = db.Transaction(func(tx *gorm.DB) error { + for _, v := range logs { + loginMID.MID, err = d.F(v, tx) + if err != nil { + logger.Logger.Errorf("Process %v error:%v", d.CollectionName, err) + return err + } + if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: failed to update %v log_mid: %v", d.CollectionName, err) + return err + } + } + return nil + }) + + return err +} diff --git a/statistics/syn/log_invitescore.go b/statistics/syn/log_invitescore.go new file mode 100644 index 0000000..fa17b14 --- /dev/null +++ b/statistics/syn/log_invitescore.go @@ -0,0 +1,291 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mymongo "mongo.games.com/game/mongo" + mymysql "mongo.games.com/game/mysql" + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" + "mongo.games.com/goserver/core/logger" +) + +func SyncInviteScore(platform string, batchSize int) error { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to get database: %v", err) + return err + } + inviteMID := &mysqlmodel.LogInviteScoreMid{ID: 1} + var n int64 + err = db.Model(&mysqlmodel.LogInviteScoreMid{}).Find(inviteMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to get log_invitescore_mid: %v", err) + return err + } + if n == 0 { + if err = db.Create(inviteMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invitescore_mid: %v", err) + return err + } + } + + logger.Logger.Tracef("start SyncInviteScore log_invitescore _id:%v", inviteMID.MID) + + _id, _ := primitive.ObjectIDFromHex(inviteMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogInviteScore) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogInviteScore, err) + return err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) + return err + } + + var logs []*mongomodel.InviteScore + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return err + } + + logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) + return err + } + l.Close(context.TODO()) + + getPSnId := func(tx *gorm.DB, snid int) (int, error) { + if snid <= 0 { + return 0, nil + } + ret := new(mysqlmodel.LogInviteUser) + if err = tx.First(ret, "snid = ? and level = 1", snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncInviteScore failed to getPSnId: %v", err) + return 0, err + } + return ret.Psnid, nil + } + + getDownSnId := func(tx *gorm.DB, snid []int) ([]int, error) { + if len(snid) == 0 { + return nil, nil + } + var ret []int + var us []*mysqlmodel.LogInviteUser + if err = tx.Select("snid").Where("psnid IN ? AND level = 1", snid).Find(&us).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncInviteScore failed to getDownSnId: %v", err) + return ret, err + } + for _, v := range us { + ret = append(ret, v.Snid) + } + return ret, nil + } + + bind := func(tx *gorm.DB, psnid, snid int, ts int) ([]*mysqlmodel.LogInviteUser, error) { + var lu []*mysqlmodel.LogInviteUser + var a1, a2, a3, a4, b1 int + var b2, b3, b4 []int + a4 = psnid + a3, err = getPSnId(tx, a4) + if err != nil { + return nil, err + } + a2, err = getPSnId(tx, a3) + if err != nil { + return nil, err + } + a1, err = getPSnId(tx, a2) + if err != nil { + return nil, err + } + b1 = snid + b2, err = getDownSnId(tx, []int{b1}) + if err != nil { + return nil, err + } + b3, err = getDownSnId(tx, b2) + if err != nil { + return nil, err + } + b4, err = getDownSnId(tx, b3) + if err != nil { + return nil, err + } + logger.Logger.Tracef("a1:%d, a2:%d, a3:%d, a4:%d, b1:%d, b2:%v, b3:%v, b4:%v", a1, a2, a3, a4, b1, b2, b3, b4) + if a1 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a1, + Snid: b1, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a1: %v %v %v", b1, 4, ts) + } + } + if a2 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a2, + Snid: b1, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a2: %v %v %v", b1, 3, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a2, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a2: %v %v %v", v, 4, ts) + } + } + if a3 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: b1, + Level: 2, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", b1, 2, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: v, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", v, 3, ts) + } + for _, v := range b3 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", v, 4, ts) + } + } + if a4 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: b1, + Level: 1, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", b1, 1, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 2, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 2, ts) + } + for _, v := range b3 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 3, ts) + } + for _, v := range b4 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 4, ts) + } + } + return lu, nil + } + + for _, v := range logs { + err = db.Transaction(func(tx *gorm.DB) error { + inviteMID.MID = v.Id.Hex() + if err = tx.Model(inviteMID).Updates(inviteMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to update log_invitescore_mid: %v", err) + return err + } + + err = tx.Save(&mysqlmodel.LogInviteScore{ + UpSnid: v.UpSnid, + DownSnid: v.DownSnid, + Level: v.Level, + Tp: v.Tp, + Rate: v.Rate, + Score: v.Score, + Money: v.Money, + Ts: v.Ts, + }).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to insert: %v", err) + return err + } + + if v.Tp == constant.InviteScoreTypeBind && v.Level == 0 { + // 绑定关系 + lu, err := bind(tx, v.UpSnid, v.DownSnid, v.Ts) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to bind: %v", err) + return err + } + if err = tx.CreateInBatches(lu, len(lu)).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invite_user: %v", err) + return err + } + } + + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to transaction: %v", err) + return err + } + } + return nil +} diff --git a/statistics/syn/log_itemgain.go b/statistics/syn/log_itemgain.go new file mode 100644 index 0000000..80b828b --- /dev/null +++ b/statistics/syn/log_itemgain.go @@ -0,0 +1,61 @@ +package syn + +import ( + "errors" + "time" + + "gorm.io/gorm" + + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" +) + +func ItemGainDone(data *Data[mongomodel.ItemLog]) error { + data.MidType = mysqlmodel.MidTypeItem + data.Database = constant.Log + data.CollectionName = mongomodel.LogItem + data.F = func(data *mongomodel.ItemLog, db *gorm.DB) (string, error) { + if data == nil || data.LogId.Hex() == "" { + return "", errors.New("null") + } + if data.LogType != 0 || data.Id != "" { + return data.LogId.Hex(), nil + } + + hourTime := time.Unix(data.CreateTs, 0).Local() + hourTs := time.Date(hourTime.Year(), hourTime.Month(), hourTime.Day(), hourTime.Hour(), 0, 0, 0, time.Local).Unix() + + item := &mysqlmodel.ItemGain{} + err := db.Model(item).Where("hour = ? and item_id = ?", hourTs, data.ItemId).First(item).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + item.Hour = hourTs + item.ItemId = data.ItemId + item.ItemNum += data.Count + if item.ID == 0 { + err = db.Create(item).Error + } else { + err = db.Model(item).Updates(item).Error + } + if err != nil { + return "", err + } + + itemTotal := &mysqlmodel.ItemTotalGain{} + err = db.Model(itemTotal).Where("item_id = ?", data.ItemId).First(itemTotal).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + itemTotal.ItemId = data.ItemId + itemTotal.ItemNum += data.Count + if itemTotal.ID == 0 { + err = db.Create(itemTotal).Error + } else { + err = db.Model(itemTotal).Updates(itemTotal).Error + } + return data.LogId.Hex(), err + } + return data.CommonDone() +} diff --git a/statistics/syn/log_login.go b/statistics/syn/log_login.go new file mode 100644 index 0000000..01260e5 --- /dev/null +++ b/statistics/syn/log_login.go @@ -0,0 +1,182 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mymongo "mongo.games.com/game/mongo" + mymysql "mongo.games.com/game/mysql" + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" + "mongo.games.com/goserver/core/logger" +) + +/* + 登录日志同步使用了mongo的_id,从小到大每次同步n个 +*/ + +// LogLogin 同步登录日志 +func LogLogin(platform string, batchSize int) ([]*mysqlmodel.LogLogin, error) { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get database: %v", err) + return nil, err + } + loginMID := &mysqlmodel.LogLoginMid{ID: 1} + var n int64 + err = db.Model(&mysqlmodel.LogLoginMid{}).Find(loginMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login_mid: %v", err) + return nil, err + } + if n == 0 { + if err = db.Create(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login_mid: %v", err) + return nil, err + } + } + + logger.Logger.Tracef("start SyncLogLogin log_login _id:%v", loginMID.MID) + + _id, _ := primitive.ObjectIDFromHex(loginMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) + return nil, err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: SyncLogLogin failed to get log_login: %v", err) + return nil, err + } + + var logs []*mongomodel.LoginLog + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + + logger.Logger.Errorf("mongo: SyncLogLogin failed to get loginlog: %v", err) + return nil, err + } + l.Close(context.TODO()) + + var ls []*mysqlmodel.LogLogin + for _, v := range logs { + logger.Logger.Tracef("mongo SyncLogLogin log_login: %+v", *v) + var e *mysqlmodel.LogLogin + switch v.LogType { + case mongomodel.LogTypeLogin, mongomodel.LogTypeRehold: + onlineType := mysqlmodel.LogTypeLogin + if v.LogType == mongomodel.LogTypeRehold { + onlineType = mysqlmodel.LogTypeRehold + } + + // 创建数据 + var n int64 + if err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ? AND online_type = ? AND online_time = ?", + v.SnId, onlineType, v.Time).Count(&n).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login count: %v", err) + return ls, err + } + + if n == 0 { + e = &mysqlmodel.LogLogin{ + Snid: int(v.SnId), + OnlineType: onlineType, + //OnlineTs: int(v.Ts), + OnlineTime: v.Time, + OfflineType: 0, + //OfflineTs: 0, + OfflineTime: v.Time, + DeviceName: v.DeviceName, + AppVersion: v.AppVersion, + BuildVersion: v.BuildVersion, + AppChannel: v.AppChannel, + ChannelId: v.ChannelId, + } + if err = db.Create(e).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login: %v", err) + return ls, err + } + } else { + continue + } + + case mongomodel.LogTypeLogout, mongomodel.LogTypeDrop: + // 修改数据 + e = &mysqlmodel.LogLogin{} + err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ?", v.SnId).Order("online_time DESC").First(e).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncLogLogin failed to find log_login: %v", err) + return ls, err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Warnf("mysql: SyncLogLogin not found log_login: %v", v) + continue + } + + if e.OfflineType != 0 { + logger.Logger.Tracef("mysql: SyncLogLogin already offline: %+v", *e) + continue + } + + e.OfflineType = mysqlmodel.LogTypeOffline + //e.OfflineTs = int(v.Ts) + e.OfflineTime = v.Time + if err = db.Model(e).Select("OfflineType", "OfflineTime").Updates(e).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login: %v", err) + return ls, err + } + default: + continue + } + + if e != nil { + ls = append(ls, e) + } + } + + if len(logs) > 0 { + err = db.Transaction(func(tx *gorm.DB) error { + loginMID.MID = logs[len(logs)-1].LogId.Hex() + if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login_mid: %v", err) + return err + } + + for _, v := range ls { + if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.Snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncLogLogin failed to find user_id: %v", err) + return err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + if err = tx.Create(&mysqlmodel.UserID{Snid: v.Snid}).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create user_id: %v", err) + return err + } + } + } + + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to transaction: %v", err) + return nil, err + } + } + + return ls, nil +} diff --git a/statistics/syn/user_account.go b/statistics/syn/user_account.go new file mode 100644 index 0000000..e3f3756 --- /dev/null +++ b/statistics/syn/user_account.go @@ -0,0 +1,106 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mymongo "mongo.games.com/game/mongo" + mymysql "mongo.games.com/game/mysql" + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/mongo/model" + mysqlmodel "mongo.games.com/game/statistics/mysql/model" + "mongo.games.com/goserver/core/logger" +) + +/* + 注册信息同步,使用mongo的_id,从小到大每次同步n个 +*/ + +// UserAccount 同步注册表 +func UserAccount(platform string, batchSize int) ([]*mysqlmodel.UserAccount, error) { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to get database: %v", err) + return nil, err + } + account := &mysqlmodel.UserAccount{} + err = db.Model(&mysqlmodel.UserAccount{}).Last(account).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: UserAccount failed to get account: %v", err) + return nil, err + } + + logger.Logger.Tracef("start UserAccount account _id:%v", account.MID) + + _id, _ := primitive.ObjectIDFromHex(account.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.UserAccount, err) + return nil, err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) + return nil, err + } + + var accounts []*mongomodel.Account + if err = l.All(context.TODO(), &accounts); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + + logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) + return nil, err + } + l.Close(context.TODO()) + + var as []*mysqlmodel.UserAccount + err = db.Transaction(func(tx *gorm.DB) error { + for _, v := range accounts { + logger.Logger.Tracef("mongo account: %+v", *v) + a := &mysqlmodel.UserAccount{ + MID: v.AccountId.Hex(), + Snid: int(v.SnId), + //RegisterTs: int(v.RegisterTs), + RegisterTime: v.RegisteTime, + Tel: v.Tel, + ChannelId: v.ChannelId, + } + + if err = tx.Create(a).Error; err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to create account: %v", err) + return err + } + + if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.SnId).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: UserAccount failed to find user_id: %v", err) + return err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + if err = tx.Create(&mysqlmodel.UserID{Snid: int(v.SnId)}).Error; err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to create user_id: %v", err) + return err + } + } + + as = append(as, a) + } + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to transaction: %v", err) + return as, err + } + return as, nil +} diff --git a/statistics/tools/logrus_hook.go b/statistics/tools/logrus_hook.go new file mode 100644 index 0000000..bdda57c --- /dev/null +++ b/statistics/tools/logrus_hook.go @@ -0,0 +1,95 @@ +package tools + +import ( + "fmt" + "runtime" + "strings" + "time" + + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/writer" +) + +// FileLineHook 新增一个字段用来打印文件路径及行号 +type FileLineHook struct { + LogLevels []logrus.Level // 需要打印的日志级别 + FieldName string // 字段名称 + Skip int // 跳过几层调用栈 + Num int // Skip后的查找范围 + Test bool // 打印所有调用栈信息,找出合适的 Skip 配置 + filename string // 文件名 + line int // 行号 +} + +func (e *FileLineHook) Levels() []logrus.Level { + return e.LogLevels +} + +func (e *FileLineHook) Fire(entry *logrus.Entry) error { + for i := 0; i < e.Num; i++ { + _, e.filename, e.line, _ = runtime.Caller(e.Skip + i) + if !strings.Contains(e.filename, "logrus") { + break + } + } + entry.Data[e.FieldName] = fmt.Sprintf("%s:%d", e.filename, e.line) + if e.Test { + buf := [4096]byte{} + n := runtime.Stack(buf[:], false) + fmt.Println(string(buf[:n])) + } + return nil +} + +// NewFileLineHook 打印文件路径及行号 +// levels 指定日志级别 +func NewFileLineHook(levels ...logrus.Level) logrus.Hook { + return &FileLineHook{ + LogLevels: levels, + FieldName: "source", + Skip: 8, + Num: 2, + } +} + +type RotateLogConfig struct { + Levels []string `json:"levels"` + Pattern string `json:"pattern"` + LinkName string `json:"link_name"` + MaxAge int `json:"max_age"` + RotationTime int `json:"rotation_time"` + RotationCount int `json:"rotation_count"` + RotationSize int `json:"rotation_size"` +} + +func NewRotateLogHook(config *RotateLogConfig) logrus.Hook { + var levels []logrus.Level + for _, v := range config.Levels { + level, err := logrus.ParseLevel(v) + if err != nil { + panic(err) + } + levels = append(levels, level) + } + + if len(levels) == 0 { + levels = logrus.AllLevels + } + + l, err := rotatelogs.New(config.Pattern, + rotatelogs.WithLinkName(config.LinkName), + rotatelogs.WithMaxAge(time.Duration(config.MaxAge)*time.Hour), + rotatelogs.WithRotationTime(time.Duration(config.RotationTime)*time.Hour), + rotatelogs.WithRotationCount(uint(config.RotationCount)), + rotatelogs.WithRotationSize(int64(config.RotationSize)), + ) + if err != nil { + panic(err) + } + + return &writer.Hook{ + Writer: l, + LogLevels: levels, + } +} diff --git a/statistics/tools/panic.go b/statistics/tools/panic.go new file mode 100644 index 0000000..b89d000 --- /dev/null +++ b/statistics/tools/panic.go @@ -0,0 +1,37 @@ +package tools + +import ( + "bytes" + "fmt" + "os" + "runtime" + "sync" +) + +var RecoverPanicFunc func(args ...interface{}) + +func init() { + bufPool := &sync.Pool{ + New: func() interface{} { + return &bytes.Buffer{} + }, + } + RecoverPanicFunc = func(args ...interface{}) { + if r := recover(); r != nil { + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + buf.WriteString(fmt.Sprintf("panic: %v\n", r)) + for _, v := range args { + buf.WriteString(fmt.Sprintf("%v\n", v)) + } + pcs := make([]uintptr, 10) + n := runtime.Callers(3, pcs) + frames := runtime.CallersFrames(pcs[:n]) + for f, again := frames.Next(); again; f, again = frames.Next() { + buf.WriteString(fmt.Sprintf("%v:%v %v\n", f.File, f.Line, f.Function)) + } + fmt.Fprint(os.Stderr, buf.String()) + } + } +} diff --git a/util/viper.go b/util/viper.go new file mode 100644 index 0000000..3b695c3 --- /dev/null +++ b/util/viper.go @@ -0,0 +1,29 @@ +package util + +import ( + "fmt" + + "github.com/spf13/viper" +) + +var paths = []string{ + ".", + "./etc", + "./config", +} + +func GetViper(name, filetype string) *viper.Viper { + vp := viper.New() + // 配置文件 + vp.SetConfigName(name) + vp.SetConfigType(filetype) + for _, v := range paths { + vp.AddConfigPath(v) + } + + err := vp.ReadInConfig() + if err != nil { + panic(fmt.Errorf("fatal error config file: %w", err)) + } + return vp +} diff --git a/worldsrv/action_lottery.go b/worldsrv/action_lottery.go index d93237f..fb23ff2 100644 --- a/worldsrv/action_lottery.go +++ b/worldsrv/action_lottery.go @@ -5,6 +5,7 @@ import ( "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/task" + "time" "mongo.games.com/game/common" "mongo.games.com/game/model" @@ -29,6 +30,7 @@ func CSLotteryInfoHandler(s *netlib.Session, packetid int, data interface{}, sid pack := &welfare.SCLotteryInfo{} + now := time.Now() var list []*welfare.LotteryInfo cfg := PlatformMgrSingleton.GetConfig(p.Platform).LotteryConfig if cfg != nil { @@ -42,8 +44,11 @@ func CSLotteryInfoHandler(s *netlib.Session, packetid int, data interface{}, sid for _, v := range list { playerLottery := info.Lottery[v.GetId()] if playerLottery != nil && playerLottery.StartTs == v.GetStartTs() { - v.CostRoomCard = playerLottery.CostCard - v.Codes = playerLottery.Code + // 活动开始和发奖期间显示 + if now.Unix() >= v.GetStartTs() && now.Unix() < v.GetWinTs() { + v.CostRoomCard = playerLottery.CostCard + v.Codes = playerLottery.Code + } } } } From 1d89a8c36e58a769eabe055fd48ed33d9910dde7 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 15 Nov 2024 15:29:00 +0800 Subject: [PATCH 18/23] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/clawdoll/scene_clawdoll.go | 2 +- webapi/deprecated.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamesrv/clawdoll/scene_clawdoll.go b/gamesrv/clawdoll/scene_clawdoll.go index 7530ee9..a725773 100644 --- a/gamesrv/clawdoll/scene_clawdoll.go +++ b/gamesrv/clawdoll/scene_clawdoll.go @@ -68,7 +68,7 @@ type SceneEx struct { machineId int //娃娃机ID machineConn *netlib.Session //娃娃机链接 machineStatus int32 //娃娃机链接状态 0:离线 1:在线 - PayCoinCount int //娃娃机总投币次数 + PayCoinCount int //娃娃机总投币次数 payCoinTimeHandle timer.TimerHandle //上分投币托管handle grabTimerHandle timer.TimerHandle //下抓托管handle diff --git a/webapi/deprecated.go b/webapi/deprecated.go index 8987d44..bbffa29 100644 --- a/webapi/deprecated.go +++ b/webapi/deprecated.go @@ -131,7 +131,7 @@ func API_CreateOrder(appId, orderId string, configid, SnId, shopId int32, platfo ExchangeOrderId: exchangeOrderId, Channel: channel, ChannelID: channelId, - BuyType: buyType, + BuyType: buyType, } ret := &webapi.ASCreateOrder{} buff, err := postRequest(appId, "/create_order", nil, body, "http", DEFAULT_TIMEOUT) From 0f1f8a03c2f3cf454a641e4761768af40dd55e47 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 15 Nov 2024 16:43:37 +0800 Subject: [PATCH 19/23] =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=88=BF=E5=A5=96?= =?UTF-8?q?=E5=93=81=E4=BB=B7=E5=80=BC=E7=BC=BA=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/rpc/svc/servicecontext.go | 4 ++-- statistics/main.go | 8 ++++---- util/{ => viperx}/viper.go | 2 +- worldsrv/customroommgr.go | 2 ++ 4 files changed, 9 insertions(+), 7 deletions(-) rename util/{ => viperx}/viper.go (96%) diff --git a/db/rpc/svc/servicecontext.go b/db/rpc/svc/servicecontext.go index 3a54cee..7f11e8c 100644 --- a/db/rpc/svc/servicecontext.go +++ b/db/rpc/svc/servicecontext.go @@ -7,8 +7,8 @@ import ( "go.mongodb.org/mongo-driver/mongo" - "mongo.games.com/game/common" mon "mongo.games.com/game/mongo" + "mongo.games.com/game/util/viperx" "mongo.games.com/goserver/core/logger" ) @@ -19,7 +19,7 @@ type ServiceContext struct { func NewServiceContext() *ServiceContext { - vp := common.GetViper("mgo", "json") + vp := viperx.GetViper("mgo", "json") // mongo初始化 conf := &mon.Config{} err := vp.Unmarshal(conf) diff --git a/statistics/main.go b/statistics/main.go index 56d81aa..dd5e27d 100644 --- a/statistics/main.go +++ b/statistics/main.go @@ -18,7 +18,7 @@ import ( "mongo.games.com/game/statistics/static" "mongo.games.com/game/statistics/syn" "mongo.games.com/game/statistics/tools" - "mongo.games.com/game/util" + "mongo.games.com/game/util/viperx" ) var VP *viper.Viper @@ -95,9 +95,9 @@ func DoTickPlatform(ctx context.Context, wg *sync.WaitGroup, duration time.Durat } func main() { - VP = util.GetViper("config", "yaml") + VP = viperx.GetViper("config", "yaml") // mongo - vp := util.GetViper("mongo", "yaml") + vp := viperx.GetViper("mongo", "yaml") // mongo初始化 conf := &mongo.Config{} err := vp.Unmarshal(conf) @@ -108,7 +108,7 @@ func main() { defer mongo.Close() // mysql - vp = util.GetViper("mysql", "yaml") + vp = viperx.GetViper("mysql", "yaml") myConf := &mysql.Config{} err = vp.Unmarshal(myConf) if err != nil { diff --git a/util/viper.go b/util/viperx/viper.go similarity index 96% rename from util/viper.go rename to util/viperx/viper.go index 3b695c3..73519eb 100644 --- a/util/viper.go +++ b/util/viperx/viper.go @@ -1,4 +1,4 @@ -package util +package viperx import ( "fmt" diff --git a/worldsrv/customroommgr.go b/worldsrv/customroommgr.go index d25d937..0445cf3 100644 --- a/worldsrv/customroommgr.go +++ b/worldsrv/customroommgr.go @@ -300,6 +300,8 @@ func (c *CustomRoomMgr) UpdateCreate(plt string, configId int32, mustCreate bool RoomConfigId: roomConfig.GetId(), CostType: 1, Voice: cfg.GetVoice(), + Price: roomConfig.GetPrice(), + ImageURL: roomConfig.GetImageURI(), }, RoomConfigSystem: cfg, IsRecruit: true, From fb02fa630e55d5fcac545ef4bf6b9d6b395197bd Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 18 Nov 2024 09:58:51 +0800 Subject: [PATCH 20/23] =?UTF-8?q?=E5=8D=81=E4=B8=89=E5=BC=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/DB_GameRule.dat | Bin 1417 -> 1417 bytes data/DB_GameRule.json | 8 ++++---- xlsx/DB_GameRule.xlsx | Bin 12969 -> 12964 bytes 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/DB_GameRule.dat b/data/DB_GameRule.dat index 01647d5a111d773234a173b527ec5d67c1770fa1..c2dfcc4f6949405f8531ae9c92d177d2046d7eaf 100644 GIT binary patch delta 32 kcmeC=?&RL^ijk3F@@qydM#jlvOvXUc3q)?NW8!880F#mjr2qf` delta 32 kcmeC=?&RL^ijk3J@@qydMvlp1OvXUc3q)?NW8!880F>?rz5oCK diff --git a/data/DB_GameRule.json b/data/DB_GameRule.json index 7c0c320..3975258 100644 --- a/data/DB_GameRule.json +++ b/data/DB_GameRule.json @@ -71,7 +71,7 @@ "Name": "十三张(四人场)", "GameId": 211, "Params": [ - 4, + 0, 0, 30, 50, @@ -84,7 +84,7 @@ "Name": "十三张(八人场)", "GameId": 212, "Params": [ - 8, + 1, 0, 30, 50, @@ -97,7 +97,7 @@ "Name": "十三张(自由场经典场)", "GameId": 213, "Params": [ - 8, + 1, 0, 30, 50, @@ -110,7 +110,7 @@ "Name": "十三张(自由场癞子场)", "GameId": 214, "Params": [ - 8, + 1, 0, 30, 50, diff --git a/xlsx/DB_GameRule.xlsx b/xlsx/DB_GameRule.xlsx index 8e4b993409d8381063ae61d67b9c3cae4a2f800c..1d7b71f567c7539b837d64b41c124552bde2f227 100644 GIT binary patch delta 4124 zcmY*ccQoAH+MO}N=ruBQobw z@vG^{P?GA}ZD+O=`4o5UU{=wN-1j5~pQBB}~~JsL@LSxp&i) zuXrdl@B`=KpR~IQ;C!pEa)Sw6t!!V!8sm-dqLS(s(oSRL3_nPrV#nwzC*2zWHM5cvMA@^=KiI9bb=AI!qt~Zt<}%Y`6{Y^`S;D> z7XyOVr*x^5)QRl7xop>9merZBt0SykTfYtzv2OG@WA&#F)F-tDP%c!+3f zgNl6k!^igXtJADrHMPV+uV0OthZHJL4G1lROO_mFejGSh_0>vxL>*FTRW7CoQa<_1?w$3zcwr$9GZRV>wPDlU_?ZM@QZ*QBc8okXq52Y&uD$ zP=G+k!XOX~gxir|1=1f7Jyx`7L#=Ht+DA^mWUR{T@b%g7TFhKQN3 zS;RJNY-J)?`fg?vemNh}>D8ziDr0lp+MVJe4z4!u(&{%gB`tqd${ug>J00J)+ARbw z%8%Csve|#T9GSS!JPPGHub>;Pqyx_T=c;#FxU9As@v6~tz>;#%&gpsP^mbL)n|Bko zGrLuK=yDv#Ot1U}De8ulFi?Q;Ld|ck+&d?jKDP^B=zp zoG=^hoD+utzO~q<5;7BMW0kMpHcmI+9qSUZ?kvK%FPy)vw4a22Hd| zKxbhWsKlRE%)4>RCkUYLg}4&;1b*&?KhJT|z?9ts-kh#CYyG;}5*>BWnqP6k;WG5T z^i+{1561GDYi_kH?Crd4=%mLVqS8U-(WpDJ0chxHofzzQr7P4eF&ixk-I5!8`=>dq zQjXq}OGH24uPLJ9`-KBBOOs2#VIpa1V-)?OTXzEwcfRm}l&jP)!Lq)n9y>#DY{u#B zxC3sWiNk68O5_6#(?Zt!`s-E}@4lHAMCp^NxECDzXTMOSZlmc8$FqkDM82Yl!gtxw zp9}wPqt&!7mXq|(LM6%ykvO@SUqkOG&-(3nk({y?yJfAeaUZovZrnXvW4%wDc@IET z%(=xXFc9+vuJwT00Ne;Krv`GHuZBM5I7SIT7Af0Zs<3MpA0ktoRtul)FjCPb5E_lLG;4&on zl>1)ur+*-vwgm5ery702NsnmNFd4MaN{%R`HH|^QdGp^jf#z?-~eh5driAi1Hc`ce0&#i3|==1M8|5x4qNgAu83y5~2 zJp3kv{p~lF0a&ENnjHX3+?w@qZP<2bjCfU-Q47^5ku-o=J}25Th^;Tpc0Pqxv$ArD{$DpEoB#md#Rp;M_?12Y%jvqC z66}!07wj25k4od$K+k+-6;*dp$*sa5t3@0;v2Do#yd=AgR&W8$!@p^M@ z3WldEzNUbLDwmWfiL8QfN363GCSKfBx+Y6ap52dZy~SFyvTG~NFu0UHIVSHlDn^Xt zm;4H^4O15{P_#7TgppF$l#GL8cuVaij?N>X>^o`nTF0wAH;|->W2T`DHpB68Akf(1 zh(DAqYiU0ZycBPkGC+#yOtGJ~3b1;vN_yFe$uo6S43xd3{5P*Ele8#_zs{kWkC&Ys zeH+}`6HbqY^{b2El>Fx+K&$*NS33KQ9#9#s6M?Rkl%bZTZ92h#jD$@Cyt-jI$hpIpiZ*&DQI|%`wp$oezm8`r{zK8jy1R@4shg|# zImK7&NZX=pXTi4Kl(z0S-2dzs!x~?Db$?-*-d9wvE~Qu$zn|%rK~DxJkDKu$kMFw? zU;nD^WH{Sy)3ckxo(hTSq@%`G0`P&cMh){hZMc1M)y(Su^w%C}OwD)sIUOkWpTwFD zLb0_9akUt=Xz8NSt(krDifN%bi1CRRO{I{I4Igiba2YpVhS-27M_P2Quqn1wx}3B)s10{C@W$w z!i;}U)2=>fG^b$eL1Av^aI+&E9PM&$a+|2_eioX{;&S zs{f<@NbgdeXQSb^1RR4Z_2JLt@4f_&BAb#ylIad4;wmSPLVexrw)_a}4UUDyyk{&5 zju(aBW- z$5ju%buwDdcV+%MoX|Z_dL8WSkL@Fyr;9pLEuo)X%6Zk0A;&e9jv-1L6`;2ysl2&iY$Y7NO1j0f=AZ8E_5N81r?l0UOGh_~v`vI8$ zmgdTvBa1<^NeII@4K>gqyAA!54$U9uhip0^f{_Mr#F_Xa3$tWY_+}d%4gWd3J)d#? z&lTN9=H{I+{=w|rz0;w9q1#8oR7nFd77Ie$d}>b_1V)A>ltDNnRQOluzLN5!+`w^i zM<+8rojXRn5)9aB6$I>I7>q(PSPG!Hdud;>!f~l^?w_UB*<>T?#rzhlSGUSvphxSd zkC{J#@?tDxd%ZL&da06sAYQSX@D6x}|5(fWE=jJn(>4NPqT%CVyL~CqX86hTYbp3lM=_wO?;%SU2-Q#@PhtELHYrn) zJ35i0i|y{F5Z!uG|JSyebJqA4a-!RQ-pjixj*T^8>C9r^Zf@4P?VD`E^u7H%32tvj zvUZ{}{VGI1n?D4JQ{_DpnSLZYB=e%u(($M{Mx~%nZC9D2;NW<%=p?v4;iZ5gI?Twt z$K~o)&Qt=RKFrcw%1%`o_TWJN#a8r;1`mg&$@YHTEiJX3)YK4SZDJg=T%`f4?*imu zIBfzNq+a+Tt71@ z{8O5sG!i#!0dr!1E9s%zjCj1axRP_a&byG^Xz&V<38<-={2-X!ib}M{>Mjcez(w3Y z_t$&rxp`m1PCnxMh7jGIxjiy=l4N&%N4vUKUUwwLwZyd_L3LH~U9`}tIWcd4@ilsY z3%-!#+*YykJhQwzlY_M_-EKdm??r#kKAYB89J!v$#(I<7aouVMOZnEzh+=)7J;iA%5q2Njf#Dk=&w15qewdv*H{sqxO>c zjE6!T%bayfcYnrW79Xq|w$N+1kx&BTa8(jKZ2t^d|6ARP+m_G-N8=R$mH=&5cjGc@upRyK0WC>ZbuMHzh zD#^af4k8n6f+s4*-P zd=B#0Kngy=u8Rhb-|T+s%=I}tI^O3>IRU8QyA-?Be;&Hyy6Dvkm~1hSQfvE+5KOFu z`C8!-Ae(8?`{fr_$B*^A z841nmLB2Lz`KSS*892US7nH4`dEggPbjvugRL z4kru#b_J(9szt;XRS$xHKE!l$S5t0&=xC{4vh&Im^7t$sJ;bx{V`)mg-ow0P-xOh( zOrzfbUiL8V*3O(WnwlI*PP1Decf~I!G-{s9 zP!|Ga1%W`+pcwsmY)|mo0U!zy!IMKW6GL5Uxa+2{%|5e}A=+QweiA}z7pb3Yy7Z%L z1M|~jcDA>ge>i;{_1$`^mSsyuF!DeQw93bAH|}pW+jOx8l4PsAVMq-I{Z4|jZ!q9p zlNnjpg3eag0wN-6zfkaXU3BmwZhrghjd|TeYBbtRUTw^dxBL~v`kDU;-j{gjRmM5D z8wFvXo_9Nc;&n-7B4cV_`uY_Aab!+2t|lZaq8?MSis@u35HVE^*QT*(XO1-{x@(up zG+DJk?qOn3TTa&+R}V%8-#rbG)RQ2s^4l44z&v%#Goy(&++UE&^wcchRh2B5M7LJM z8!;zegx-%UDk?Rm{OtGUyndkG#PT}^@qsBS^7lr*vi9xF6PJj=qDDpF9@LhWP+pXf zN&^BNi2~USa9|5cg}1r4fME!^Yj>_bdyv%~kXaW|$X*{X-_&k1>)@)AtrR!G33OZZ zc)RS6N;p3$xbYe%b@5B8V!?x_!g2a1TWg6^0lT)fJ&j`$d4Y-vH%CIJyjD*?^8X%H zF>9OD$agf`kXx!7GmBqw^(TggoUGlwtbgnH^w82|idt$tF&@8CyT))=2w3=CJN~@K z_x_vx*&y7w%~(gy&yS0NZl!)-sD9P~PMDVl0nROn=&rQ=6vV*J{g(1=m(#k^eQqK5 zQtz>jlf;U>Ijyl!FY&&5_m3<-uaD%7`-i)Z<}J`|HZ8a;$DPT9(E(hz@db-%gAJwZ zCjX=rqIpx*=@~xYkdm2)Fj@b|>Y++-qx7p1K(XkH`(q5EXRYOBlz`!5h2qBbpWkJg zn%DbQe!aRIrZPcZ=qiL=8u*+zz8b`I%7#a|e4$1tEzbD+V=!%rjoTBW9#(IgJRr5q z360BJntPMZBLSY_KZbkne5fxx!l|9Za*N^R7bPQ}t(D_LD;Up?>6j7c6N#RoF{)P- zOO6!=>_*H!=lpatR!X}!A?{gsUMx4Y#^0FOyPvqc8*I|n9Dr_l@R%hbvmR%)S*lWU z;Bf&Q?}md}%31Z&o+k#>7XNmu5y9`O7|1TjXDgiJ1}+~qL~R>*%fp0Z8AHe07YB)b zv%`&}Q-k>GE9Cq_S&q=#TVJ`par+Ao_X~yR$QnIX(HDOSn|-vs1>{ROf!3yCGW|8D zQfznQS0D4(@Dc z<6?!K@b))X08Wn-Om;%}+sd$IsgeS*C>gC+(!MQMk5V2lTT9h8eU7G}ue5&;awuj> z6lTSr@EUC?+}NbZTYPvk#d6IxjR_i8vfXP_A*7=$R6B+s4 zMcr*lBX8kPJ~YD|*{@+4oCNhfq1--DOlc$KH4?8y1IKUt0_I>cQ%oTPXNM|V;_v)a zOvgepU2c__ACtD8-~hYmO>4$kuLeRa7+rs@2^>s<9W%qw-%`Vczzi9Y>uj5y39o42 zg+v?LeKt8VybtOFGmcNsFnVvu8|Sj#2q7)9lE!a;KiS~C;~!ESoP4$ zm=@gH+Qb8a4ut%O))crSaES67db=$#hQfS$)_dE$Uju`!kZRug-cP7GB@u_p6a^4{ zzx|%VoxZpYW~=ZH*t$~ti~<8kj030W;nY>_M=UttI}2Fx&2|w zt#>sfKCIEb+W(}3?vZDow*EsFDDx2IKmiMb<51?uIQ>R&ZZvT ziCwHV9ReM~3|!`z+Cgy9kx?GUq<7<74L`mS$FxsO!(LaW>Y6Ht$?%B!Lwu-Xa*EOI zd}R_UBwqX1ni~y}PH8Y-nOM{Th%p*`uV=^l{Kg;VAu(503%$vYBn<>7*d zxY30to#s}wS+jXam`OB^@p9_~c_FiGJK8IoU_;Z#Xm31K9j)sEwxkVy;q!lVHdF_)Kyu@c!cO9Us^4%%i*M@&S^86tztJ| z`-(gLNn+1dV+!=DeYzCr@J)8k(cy&C3YfuuM8=t@+Nx?|OuN9al4AVbL)U&M>s}x+ zJ7wm_lT&&`@Tk&DAr2}7yqZwRqh)|bRi1z4n;up+!Pfs?Iu^G7gdwarR}$w|q8MEP z4Uiud3G*$x@jYLN==02Q?!t`HR%l z`hUpBNGwEtxZI3l!91>#tP7tLe$}K1e#N|sAcx>{p%?jdpoQUnNz77zP3ke?r{Xdk z5F$*|KsX~3$C{>xeG`e%^qZ;3OPjxh477E+O0A*O%hAgGUE8Jt`q!r!K3%HQNUc7K zLJj%#ddl$`mgaJ}TZJG&k1|7x2Hs^xVO6&Fyj|Xu-;3S&ro2vXgSUYm>>mTjxL;H{ zKGMUs+Monj3|VKDFf^kViiqBk}a;wXTJXz zu6SJ;BUvfeBw@=y%wHu8b&Y&hdQJ3MOq%jovNM#>+zP1`ye>ke$#U=A*n7Cc-T_p24ujFulFS3!KI(XPCu&!WyGZt}QLzpG$ zR{qkgAnDKk%wm2%e|)Mn`1LQzA1o5;Q87HNbnQWhw268!`Lew@GKac{vWZMeFm52@ zW%s>H=KTtten;-JQ0}u%x?pP!&?_deAe>X3H3LfbC(NoX^TQ-P~Gr zyGO~?Cd1vFrGszj6zROw43pvRx^*@w&3y{qxfaxBIyGVcK=`7`aqSsTa|+FcuQf8w zbdzn6=2(VX6SdA$8FDg`VTlIOFie1zxOSmFU471z)(v|nRh7^w*=V2CGqkD zvJU2G#oXxr!%6S7x8z6hEiXHqF6Pon^Ep&be>3S3_ib9E|p;~ zfyH`w%fo1%Mv?24cHV3G?yMGQA1HMnt$Z@)^*53ZeeT^Op4P3sftR!#FUaw9%ralR z%Aal+A?9r(IO3`Te&L(a6$L-imx zLx$d4kF>3S0+q8_{m>;@Pp8j(`j}&FcUwhnx}~GYnX1lQph(3k;bLQemgDbzo;)1W z$Uw^1Ri`4gY4-A~^p@r^r91<-2kxGhE?iR*C+o08y;rZi;DF zT4~RjU-0dC*ALEdRGm1=8T=eaq1@w8(*WFN17Ddkh}r6}+TpvD0K0kS4al5p-8iGD zwnua`fvo`{aV)eB1p=j@*#Lq#CwLsl5(oY#GhdUyK>ta4z7lL;I1np=rSgS>K!IKo z06`J~5SXFBrUWeog$QsgAp=GMl4vome|`=H2oysN0{zX4e+vxa{nHJAAhar&05qX7 zU=Ls)EelQt#3Zp`7XT-z2u=Y?CHWBlmzO{wj=!US>fh;BC@=x#1Sq7gf}a3lQX1e# Nz Date: Mon, 18 Nov 2024 18:08:37 +0800 Subject: [PATCH 21/23] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/time.go | 6 ++++++ protocol/webapi/common.pb.go | 8 ++++---- protocol/webapi/common.proto | 8 ++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/common/time.go b/common/time.go index 4dc02fe..e54bfaa 100644 --- a/common/time.go +++ b/common/time.go @@ -130,6 +130,7 @@ func TsToStrTime(tc int64) string { //return time.Now().Format("2018-07-02 19:14:00") return time.Unix(tc, 0).Format("2006-01-02 15:04:05") } + func TsToStrDateTime(tc int64) string { //return time.Now().Format("2018-07-02 19:14:00") return time.Unix(tc, 0).Format("2006-01-02") @@ -198,3 +199,8 @@ func HMSToTime(h, m, s int) time.Time { func IntToTime(n int) time.Time { return HMSToTime(n/10000, n%10000/100, n%100) } + +func StrTimeToTime(s string) time.Time { + t, _ := time.ParseInLocation("2006-01-02 15:04:05", s, time.Local) + return t +} diff --git a/protocol/webapi/common.pb.go b/protocol/webapi/common.pb.go index 1d878e7..a8e4bfc 100644 --- a/protocol/webapi/common.pb.go +++ b/protocol/webapi/common.pb.go @@ -3681,10 +3681,10 @@ type ShopWeight struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ShopType int32 `protobuf:"varint,1,opt,name=ShopType,proto3" json:"ShopType,omitempty"` - Weight int32 `protobuf:"varint,2,opt,name=Weight,proto3" json:"Weight,omitempty"` - Name string `protobuf:"bytes,3,opt,name=Name,proto3" json:"Name,omitempty"` - IsShow int32 `protobuf:"varint,4,opt,name=IsShow,proto3" json:"IsShow,omitempty"` + ShopType int32 `protobuf:"varint,1,opt,name=ShopType,proto3" json:"ShopType,omitempty"` // 商品类型 对应 ExchangeShop.ShopType + Weight int32 `protobuf:"varint,2,opt,name=Weight,proto3" json:"Weight,omitempty"` // 排序,从大到小 + Name string `protobuf:"bytes,3,opt,name=Name,proto3" json:"Name,omitempty"` // 分类名称, 多语言 {\"zh\":\"电子\",\"en\":\"electronic engineering\",\"vi\":\"Điện tử\",\"kh\":\"អេឡិចត្រូន\"} + IsShow int32 `protobuf:"varint,4,opt,name=IsShow,proto3" json:"IsShow,omitempty"` // 是否显示 1显示 Location []int32 `protobuf:"varint,5,rep,packed,name=Location,proto3" json:"Location,omitempty"` // 显示位置 } diff --git a/protocol/webapi/common.proto b/protocol/webapi/common.proto index 1e03fd4..c1cb5fb 100644 --- a/protocol/webapi/common.proto +++ b/protocol/webapi/common.proto @@ -419,10 +419,10 @@ message ExchangeShopList{ } message ShopWeight{ - int32 ShopType = 1; - int32 Weight = 2; - string Name = 3; - int32 IsShow = 4; + int32 ShopType = 1; // 商品类型 对应 ExchangeShop.ShopType + int32 Weight = 2; // 排序,从大到小 + string Name = 3; // 分类名称, 多语言 {\"zh\":\"电子\",\"en\":\"electronic engineering\",\"vi\":\"Điện tử\",\"kh\":\"អេឡិចត្រូន\"} + int32 IsShow = 4; // 是否显示 1显示 repeated int32 Location = 5; // 显示位置 } From 46ad7ea75f97a4aa9abab0f36614270b85b6cb0f Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 19 Nov 2024 10:29:34 +0800 Subject: [PATCH 22/23] =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/dao/internal/user.go | 312 -------- db/dao/user.go | 22 - db/gen.bat | 2 - db/model/user.go | 25 - db/proto/public.proto | 10 - db/proto/public/public.pb.go | 151 ---- db/proto/user.proto | 21 - db/proto/user/user.pb.go | 235 ------ db/proto/user/user_grpc.pb.go | 109 --- db/rpc/export.go | 58 -- db/rpc/logic/userlogic.go | 34 - db/rpc/server/userserver.go | 29 - db/rpc/svc/servicecontext.go | 97 --- gamesrv/base/player.go | 4 +- go.mod | 4 +- go.sum | 7 +- model/dataevent.go | 667 +++++++++--------- mongo/export.go | 145 ---- mongo/internal/mongo.go | 196 ----- statistics/.gitignore | 27 - statistics/README.md | 8 - statistics/build_linux.bat | 8 - statistics/constant/constant.go | 13 - statistics/etc/config.yaml | 27 - statistics/etc/mongo.yaml | 53 -- statistics/etc/mysql.yaml | 31 - statistics/local_test.go | 53 -- statistics/logger.xml | 22 - statistics/main.go | 239 ------- .../mongo/model/log_gameplayerlistlog.go | 47 -- statistics/mongo/model/log_invitescore.go | 19 - statistics/mongo/model/log_item.go | 27 - statistics/mongo/model/log_login.go | 33 - statistics/mongo/model/user_account.go | 24 - statistics/mysql/model/init.go | 17 - statistics/mysql/model/log_invitescore.go | 26 - statistics/mysql/model/log_itemgain.go | 16 - statistics/mysql/model/log_login.go | 26 - statistics/mysql/model/log_login_mid.go | 6 - statistics/mysql/model/log_mid.go | 11 - statistics/mysql/model/user_account.go | 18 - statistics/mysql/model/user_id.go | 9 - statistics/mysql/model/user_login.go | 29 - statistics/shell/close.sh | 4 - statistics/shell/start.sh | 2 - statistics/static/init.go | 1 - statistics/static/user_login.go | 372 ---------- statistics/syn/init.go | 102 --- statistics/syn/log_invitescore.go | 291 -------- statistics/syn/log_itemgain.go | 61 -- statistics/syn/log_login.go | 182 ----- statistics/syn/user_account.go | 106 --- statistics/tools/logrus_hook.go | 95 --- statistics/tools/panic.go | 37 - 54 files changed, 333 insertions(+), 3837 deletions(-) delete mode 100644 db/dao/internal/user.go delete mode 100644 db/dao/user.go delete mode 100644 db/gen.bat delete mode 100644 db/model/user.go delete mode 100644 db/proto/public.proto delete mode 100644 db/proto/public/public.pb.go delete mode 100644 db/proto/user.proto delete mode 100644 db/proto/user/user.pb.go delete mode 100644 db/proto/user/user_grpc.pb.go delete mode 100644 db/rpc/export.go delete mode 100644 db/rpc/logic/userlogic.go delete mode 100644 db/rpc/server/userserver.go delete mode 100644 db/rpc/svc/servicecontext.go delete mode 100644 mongo/export.go delete mode 100644 mongo/internal/mongo.go delete mode 100644 statistics/.gitignore delete mode 100644 statistics/README.md delete mode 100644 statistics/build_linux.bat delete mode 100644 statistics/constant/constant.go delete mode 100644 statistics/etc/config.yaml delete mode 100644 statistics/etc/mongo.yaml delete mode 100644 statistics/etc/mysql.yaml delete mode 100644 statistics/local_test.go delete mode 100644 statistics/logger.xml delete mode 100644 statistics/main.go delete mode 100644 statistics/mongo/model/log_gameplayerlistlog.go delete mode 100644 statistics/mongo/model/log_invitescore.go delete mode 100644 statistics/mongo/model/log_item.go delete mode 100644 statistics/mongo/model/log_login.go delete mode 100644 statistics/mongo/model/user_account.go delete mode 100644 statistics/mysql/model/init.go delete mode 100644 statistics/mysql/model/log_invitescore.go delete mode 100644 statistics/mysql/model/log_itemgain.go delete mode 100644 statistics/mysql/model/log_login.go delete mode 100644 statistics/mysql/model/log_login_mid.go delete mode 100644 statistics/mysql/model/log_mid.go delete mode 100644 statistics/mysql/model/user_account.go delete mode 100644 statistics/mysql/model/user_id.go delete mode 100644 statistics/mysql/model/user_login.go delete mode 100644 statistics/shell/close.sh delete mode 100644 statistics/shell/start.sh delete mode 100644 statistics/static/init.go delete mode 100644 statistics/static/user_login.go delete mode 100644 statistics/syn/init.go delete mode 100644 statistics/syn/log_invitescore.go delete mode 100644 statistics/syn/log_itemgain.go delete mode 100644 statistics/syn/log_login.go delete mode 100644 statistics/syn/user_account.go delete mode 100644 statistics/tools/logrus_hook.go delete mode 100644 statistics/tools/panic.go diff --git a/db/dao/internal/user.go b/db/dao/internal/user.go deleted file mode 100644 index 93d61d0..0000000 --- a/db/dao/internal/user.go +++ /dev/null @@ -1,312 +0,0 @@ -// -------------------------------------------------------------------------------------------- -// The following code is automatically generated by the mongo-dao-generator tool. -// Please do not modify this code manually to avoid being overwritten in the next generation. -// For more tool details, please click the link to view https://github.com/dobyte/mongo-dao-generator -// -------------------------------------------------------------------------------------------- - -package internal - -import ( - "context" - "errors" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - modelpkg "mongo.games.com/game/db/model" - "time" -) - -type UserFilterFunc func(cols *UserColumns) interface{} -type UserUpdateFunc func(cols *UserColumns) interface{} -type UserPipelineFunc func(cols *UserColumns) interface{} -type UserCountOptionsFunc func(cols *UserColumns) *options.CountOptions -type UserAggregateOptionsFunc func(cols *UserColumns) *options.AggregateOptions -type UserFindOneOptionsFunc func(cols *UserColumns) *options.FindOneOptions -type UserFindManyOptionsFunc func(cols *UserColumns) *options.FindOptions -type UserUpdateOptionsFunc func(cols *UserColumns) *options.UpdateOptions -type UserDeleteOptionsFunc func(cols *UserColumns) *options.DeleteOptions -type UserInsertOneOptionsFunc func(cols *UserColumns) *options.InsertOneOptions -type UserInsertManyOptionsFunc func(cols *UserColumns) *options.InsertManyOptions - -type User struct { - Columns *UserColumns - Database *mongo.Database - Collection *mongo.Collection -} - -type UserColumns struct { - ID string - Account string // 用户账号 - Password string // 用户密码 - Salt string // 密码 - Mobile string // 用户手机 - Email string // 用户邮箱 - Nickname string // 用户昵称 - Signature string // 用户签名 - Level string // 用户等级 - Experience string // 用户经验 - Coin string // 用户金币 - DeviceID string // 设备ID - RegisterIP string // 注册IP - RegisterTime string // 注册时间 - LastLoginIP string // 最近登录IP - LastLoginTime string // 最近登录时间 -} - -var userColumns = &UserColumns{ - ID: "_id", - Account: "account", // 用户账号 - Password: "password", // 用户密码 - Salt: "salt", // 密码 - Mobile: "mobile", // 用户手机 - Email: "email", // 用户邮箱 - Nickname: "nickname", // 用户昵称 - Signature: "signature", // 用户签名 - Level: "level", // 用户等级 - Experience: "experience", // 用户经验 - Coin: "coin", // 用户金币 - DeviceID: "device_id", // 设备ID - RegisterIP: "register_ip", // 注册IP - RegisterTime: "register_time", // 注册时间 - LastLoginIP: "last_login_ip", // 最近登录IP - LastLoginTime: "last_login_time", // 最近登录时间 -} - -func NewUser(db *mongo.Database) *User { - return &User{ - Columns: userColumns, - Database: db, - Collection: db.Collection("user"), - } -} - -// Count returns the number of documents in the collection. -func (dao *User) Count(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserCountOptionsFunc) (int64, error) { - var ( - opts *options.CountOptions - filter = filterFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.CountDocuments(ctx, filter, opts) -} - -// Aggregate executes an aggregate command against the collection and returns a cursor over the resulting documents. -func (dao *User) Aggregate(ctx context.Context, pipelineFunc UserPipelineFunc, optionsFunc ...UserAggregateOptionsFunc) (*mongo.Cursor, error) { - var ( - opts *options.AggregateOptions - pipeline = pipelineFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.Aggregate(ctx, pipeline, opts) -} - -// InsertOne executes an insert command to insert a single document into the collection. -func (dao *User) InsertOne(ctx context.Context, model *modelpkg.User, optionsFunc ...UserInsertOneOptionsFunc) (*mongo.InsertOneResult, error) { - if model == nil { - return nil, errors.New("model is nil") - } - - if err := dao.autofill(ctx, model); err != nil { - return nil, err - } - - var opts *options.InsertOneOptions - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.InsertOne(ctx, model, opts) -} - -// InsertMany executes an insert command to insert multiple documents into the collection. -func (dao *User) InsertMany(ctx context.Context, models []*modelpkg.User, optionsFunc ...UserInsertManyOptionsFunc) (*mongo.InsertManyResult, error) { - if len(models) == 0 { - return nil, errors.New("models is empty") - } - - documents := make([]interface{}, 0, len(models)) - for i := range models { - model := models[i] - if err := dao.autofill(ctx, model); err != nil { - return nil, err - } - documents = append(documents, model) - } - - var opts *options.InsertManyOptions - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.InsertMany(ctx, documents, opts) -} - -// UpdateOne executes an update command to update at most one document in the collection. -func (dao *User) UpdateOne(ctx context.Context, filterFunc UserFilterFunc, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*mongo.UpdateResult, error) { - var ( - opts *options.UpdateOptions - filter = filterFunc(dao.Columns) - update = updateFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.UpdateOne(ctx, filter, update, opts) -} - -// UpdateOneByID executes an update command to update at most one document in the collection. -func (dao *User) UpdateOneByID(ctx context.Context, id string, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*mongo.UpdateResult, error) { - objectID, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, err - } - - return dao.UpdateOne(ctx, func(cols *UserColumns) interface{} { - return bson.M{"_id": objectID} - }, updateFunc, optionsFunc...) -} - -// UpdateMany executes an update command to update documents in the collection. -func (dao *User) UpdateMany(ctx context.Context, filterFunc UserFilterFunc, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*mongo.UpdateResult, error) { - var ( - opts *options.UpdateOptions - filter = filterFunc(dao.Columns) - update = updateFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.UpdateMany(ctx, filter, update, opts) -} - -// FindOne executes a find command and returns a model for one document in the collection. -func (dao *User) FindOne(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserFindOneOptionsFunc) (*modelpkg.User, error) { - var ( - opts *options.FindOneOptions - model = &modelpkg.User{} - filter = filterFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - err := dao.Collection.FindOne(ctx, filter, opts).Decode(model) - if err != nil { - if err == mongo.ErrNoDocuments { - return nil, nil - } - return nil, err - } - - return model, nil -} - -// FindOneByID executes a find command and returns a model for one document in the collection. -func (dao *User) FindOneByID(ctx context.Context, id string, optionsFunc ...UserFindOneOptionsFunc) (*modelpkg.User, error) { - objectID, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, err - } - - return dao.FindOne(ctx, func(cols *UserColumns) interface{} { - return bson.M{"_id": objectID} - }, optionsFunc...) -} - -// FindMany executes a find command and returns many models the matching documents in the collection. -func (dao *User) FindMany(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserFindManyOptionsFunc) ([]*modelpkg.User, error) { - var ( - opts *options.FindOptions - filter = filterFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - cur, err := dao.Collection.Find(ctx, filter, opts) - if err != nil { - return nil, err - } - - models := make([]*modelpkg.User, 0) - - if err = cur.All(ctx, &models); err != nil { - return nil, err - } - - return models, nil -} - -// DeleteOne executes a delete command to delete at most one document from the collection. -func (dao *User) DeleteOne(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserDeleteOptionsFunc) (*mongo.DeleteResult, error) { - var ( - opts *options.DeleteOptions - filter = filterFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.DeleteOne(ctx, filter, opts) -} - -// DeleteOneByID executes a delete command to delete at most one document from the collection. -func (dao *User) DeleteOneByID(ctx context.Context, id string, optionsFunc ...UserDeleteOptionsFunc) (*mongo.DeleteResult, error) { - objectID, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, err - } - - return dao.DeleteOne(ctx, func(cols *UserColumns) interface{} { - return bson.M{"_id": objectID} - }, optionsFunc...) -} - -// DeleteMany executes a delete command to delete documents from the collection. -func (dao *User) DeleteMany(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserDeleteOptionsFunc) (*mongo.DeleteResult, error) { - var ( - opts *options.DeleteOptions - filter = filterFunc(dao.Columns) - ) - - if len(optionsFunc) > 0 { - opts = optionsFunc[0](dao.Columns) - } - - return dao.Collection.DeleteMany(ctx, filter, opts) -} - -// autofill when inserting data -func (dao *User) autofill(ctx context.Context, model *modelpkg.User) error { - if model.ID.IsZero() { - model.ID = primitive.NewObjectID() - } - - if model.RegisterTime == 0 { - model.RegisterTime = primitive.NewDateTimeFromTime(time.Now()) - } - - if model.LastLoginTime == 0 { - model.LastLoginTime = primitive.NewDateTimeFromTime(time.Now()) - } - - return nil -} diff --git a/db/dao/user.go b/db/dao/user.go deleted file mode 100644 index a7757ad..0000000 --- a/db/dao/user.go +++ /dev/null @@ -1,22 +0,0 @@ -package dao - -import ( - "go.mongodb.org/mongo-driver/mongo" - "mongo.games.com/game/db/dao/internal" -) - -type UserColumns = internal.UserColumns - -type User struct { - *internal.User -} - -func NewUser(db *mongo.Database, c *mongo.Collection) *User { - v := internal.NewUser(nil) - v.Database = db - v.Collection = c - panic("创建索引") - //c.Indexes().CreateOne() - //c.Indexes().CreateMany() - return &User{User: v} -} diff --git a/db/gen.bat b/db/gen.bat deleted file mode 100644 index 7342b59..0000000 --- a/db/gen.bat +++ /dev/null @@ -1,2 +0,0 @@ -mongoctl -model-dir=./model -model-names=User -dao-dir=./dao -protoc --proto_path=./proto --go_out=../../../ --go-grpc_out=../../../ ./proto/*.proto \ No newline at end of file diff --git a/db/model/user.go b/db/model/user.go deleted file mode 100644 index 8838d95..0000000 --- a/db/model/user.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -import ( - "go.mongodb.org/mongo-driver/bson/primitive" -) - -//go:generate mongoctl -model-dir=. -model-names=User -dao-dir=../dao -type User struct { - ID primitive.ObjectID `bson:"_id" gen:"autoFill"` - Account string `bson:"account"` // 用户账号 - Password string `bson:"password"` // 用户密码 - Salt string `bson:"salt"` // 密码 - Mobile string `bson:"mobile"` // 用户手机 - Email string `bson:"email"` // 用户邮箱 - Nickname string `bson:"nickname"` // 用户昵称 - Signature string `bson:"signature"` // 用户签名 - Level int `bson:"level"` // 用户等级 - Experience int `bson:"experience"` // 用户经验 - Coin int `bson:"coin"` // 用户金币 - DeviceID string `bson:"device_id"` // 设备ID - RegisterIP string `bson:"register_ip"` // 注册IP - RegisterTime primitive.DateTime `bson:"register_time" gen:"autoFill"` // 注册时间 - LastLoginIP string `bson:"last_login_ip"` // 最近登录IP - LastLoginTime primitive.DateTime `bson:"last_login_time" gen:"autoFill"` // 最近登录时间 -} diff --git a/db/proto/public.proto b/db/proto/public.proto deleted file mode 100644 index f92b031..0000000 --- a/db/proto/public.proto +++ /dev/null @@ -1,10 +0,0 @@ -syntax = "proto3"; -package public; -option go_package = "mongo.games.com/game/db/proto/public"; - -// 通用数据结构 - -message Item { - int32 Id = 1; // id - int64 Num = 2; // 数量 -} \ No newline at end of file diff --git a/db/proto/public/public.pb.go b/db/proto/public/public.pb.go deleted file mode 100644 index cd960c1..0000000 --- a/db/proto/public/public.pb.go +++ /dev/null @@ -1,151 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.27.1-devel -// protoc v3.19.4 -// source: public.proto - -package public - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Item struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int32 `protobuf:"varint,1,opt,name=Id,proto3" json:"Id,omitempty"` // id - Num int64 `protobuf:"varint,2,opt,name=Num,proto3" json:"Num,omitempty"` // 数量 -} - -func (x *Item) Reset() { - *x = Item{} - if protoimpl.UnsafeEnabled { - mi := &file_public_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Item) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Item) ProtoMessage() {} - -func (x *Item) ProtoReflect() protoreflect.Message { - mi := &file_public_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Item.ProtoReflect.Descriptor instead. -func (*Item) Descriptor() ([]byte, []int) { - return file_public_proto_rawDescGZIP(), []int{0} -} - -func (x *Item) GetId() int32 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Item) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -var File_public_proto protoreflect.FileDescriptor - -var file_public_proto_rawDesc = []byte{ - 0x0a, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x22, 0x28, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, - 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x49, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x4e, 0x75, 0x6d, - 0x42, 0x26, 0x5a, 0x24, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x64, 0x62, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_public_proto_rawDescOnce sync.Once - file_public_proto_rawDescData = file_public_proto_rawDesc -) - -func file_public_proto_rawDescGZIP() []byte { - file_public_proto_rawDescOnce.Do(func() { - file_public_proto_rawDescData = protoimpl.X.CompressGZIP(file_public_proto_rawDescData) - }) - return file_public_proto_rawDescData -} - -var file_public_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_public_proto_goTypes = []interface{}{ - (*Item)(nil), // 0: public.Item -} -var file_public_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_public_proto_init() } -func file_public_proto_init() { - if File_public_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_public_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Item); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_public_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_public_proto_goTypes, - DependencyIndexes: file_public_proto_depIdxs, - MessageInfos: file_public_proto_msgTypes, - }.Build() - File_public_proto = out.File - file_public_proto_rawDesc = nil - file_public_proto_goTypes = nil - file_public_proto_depIdxs = nil -} diff --git a/db/proto/user.proto b/db/proto/user.proto deleted file mode 100644 index ed50358..0000000 --- a/db/proto/user.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; -package user; -option go_package = "mongo.games.com/game/db/proto/user"; - -import "public.proto"; - -service UserServer { - rpc Save (SaveReq) returns (SaveRsp){} -} - -//客户端发送给服务端 -message SaveReq { - string Platform = 1; - string name = 2; - repeated public.Item Items = 3; -} - -//服务端返回给客户端 -message SaveRsp { - string msg = 1 ; -} \ No newline at end of file diff --git a/db/proto/user/user.pb.go b/db/proto/user/user.pb.go deleted file mode 100644 index e78ff5c..0000000 --- a/db/proto/user/user.pb.go +++ /dev/null @@ -1,235 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.27.1-devel -// protoc v3.19.4 -// source: user.proto - -package user - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - public "mongo.games.com/game/db/proto/public" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -//客户端发送给服务端 -type SaveReq struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Platform string `protobuf:"bytes,1,opt,name=Platform,proto3" json:"Platform,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Items []*public.Item `protobuf:"bytes,3,rep,name=Items,proto3" json:"Items,omitempty"` -} - -func (x *SaveReq) Reset() { - *x = SaveReq{} - if protoimpl.UnsafeEnabled { - mi := &file_user_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SaveReq) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SaveReq) ProtoMessage() {} - -func (x *SaveReq) ProtoReflect() protoreflect.Message { - mi := &file_user_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SaveReq.ProtoReflect.Descriptor instead. -func (*SaveReq) Descriptor() ([]byte, []int) { - return file_user_proto_rawDescGZIP(), []int{0} -} - -func (x *SaveReq) GetPlatform() string { - if x != nil { - return x.Platform - } - return "" -} - -func (x *SaveReq) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *SaveReq) GetItems() []*public.Item { - if x != nil { - return x.Items - } - return nil -} - -//服务端返回给客户端 -type SaveRsp struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` -} - -func (x *SaveRsp) Reset() { - *x = SaveRsp{} - if protoimpl.UnsafeEnabled { - mi := &file_user_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SaveRsp) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SaveRsp) ProtoMessage() {} - -func (x *SaveRsp) ProtoReflect() protoreflect.Message { - mi := &file_user_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SaveRsp.ProtoReflect.Descriptor instead. -func (*SaveRsp) Descriptor() ([]byte, []int) { - return file_user_proto_rawDescGZIP(), []int{1} -} - -func (x *SaveRsp) GetMsg() string { - if x != nil { - return x.Msg - } - return "" -} - -var File_user_proto protoreflect.FileDescriptor - -var file_user_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x75, 0x73, - 0x65, 0x72, 0x1a, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x5d, 0x0a, 0x07, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x49, - 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, - 0x1b, 0x0a, 0x07, 0x53, 0x61, 0x76, 0x65, 0x52, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, - 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x34, 0x0a, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x04, 0x53, 0x61, - 0x76, 0x65, 0x12, 0x0d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x0d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x73, 0x70, - 0x22, 0x00, 0x42, 0x24, 0x5a, 0x22, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, - 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x64, 0x62, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_user_proto_rawDescOnce sync.Once - file_user_proto_rawDescData = file_user_proto_rawDesc -) - -func file_user_proto_rawDescGZIP() []byte { - file_user_proto_rawDescOnce.Do(func() { - file_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_proto_rawDescData) - }) - return file_user_proto_rawDescData -} - -var file_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_user_proto_goTypes = []interface{}{ - (*SaveReq)(nil), // 0: user.SaveReq - (*SaveRsp)(nil), // 1: user.SaveRsp - (*public.Item)(nil), // 2: public.Item -} -var file_user_proto_depIdxs = []int32{ - 2, // 0: user.SaveReq.Items:type_name -> public.Item - 0, // 1: user.UserServer.Save:input_type -> user.SaveReq - 1, // 2: user.UserServer.Save:output_type -> user.SaveRsp - 2, // [2:3] is the sub-list for method output_type - 1, // [1:2] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_user_proto_init() } -func file_user_proto_init() { - if File_user_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SaveReq); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SaveRsp); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_user_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_user_proto_goTypes, - DependencyIndexes: file_user_proto_depIdxs, - MessageInfos: file_user_proto_msgTypes, - }.Build() - File_user_proto = out.File - file_user_proto_rawDesc = nil - file_user_proto_goTypes = nil - file_user_proto_depIdxs = nil -} diff --git a/db/proto/user/user_grpc.pb.go b/db/proto/user/user_grpc.pb.go deleted file mode 100644 index 94e7f93..0000000 --- a/db/proto/user/user_grpc.pb.go +++ /dev/null @@ -1,109 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v3.19.4 -// source: user.proto - -package user - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -const ( - UserServer_Save_FullMethodName = "/user.UserServer/Save" -) - -// UserServerClient is the client API for UserServer service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type UserServerClient interface { - Save(ctx context.Context, in *SaveReq, opts ...grpc.CallOption) (*SaveRsp, error) -} - -type userServerClient struct { - cc grpc.ClientConnInterface -} - -func NewUserServerClient(cc grpc.ClientConnInterface) UserServerClient { - return &userServerClient{cc} -} - -func (c *userServerClient) Save(ctx context.Context, in *SaveReq, opts ...grpc.CallOption) (*SaveRsp, error) { - out := new(SaveRsp) - err := c.cc.Invoke(ctx, UserServer_Save_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UserServerServer is the server API for UserServer service. -// All implementations must embed UnimplementedUserServerServer -// for forward compatibility -type UserServerServer interface { - Save(context.Context, *SaveReq) (*SaveRsp, error) - mustEmbedUnimplementedUserServerServer() -} - -// UnimplementedUserServerServer must be embedded to have forward compatible implementations. -type UnimplementedUserServerServer struct { -} - -func (UnimplementedUserServerServer) Save(context.Context, *SaveReq) (*SaveRsp, error) { - return nil, status.Errorf(codes.Unimplemented, "method Save not implemented") -} -func (UnimplementedUserServerServer) mustEmbedUnimplementedUserServerServer() {} - -// UnsafeUserServerServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to UserServerServer will -// result in compilation errors. -type UnsafeUserServerServer interface { - mustEmbedUnimplementedUserServerServer() -} - -func RegisterUserServerServer(s grpc.ServiceRegistrar, srv UserServerServer) { - s.RegisterService(&UserServer_ServiceDesc, srv) -} - -func _UserServer_Save_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SaveReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UserServerServer).Save(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: UserServer_Save_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UserServerServer).Save(ctx, req.(*SaveReq)) - } - return interceptor(ctx, in, info, handler) -} - -// UserServer_ServiceDesc is the grpc.ServiceDesc for UserServer service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var UserServer_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "user.UserServer", - HandlerType: (*UserServerServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Save", - Handler: _UserServer_Save_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "user.proto", -} diff --git a/db/rpc/export.go b/db/rpc/export.go deleted file mode 100644 index 9b4fd69..0000000 --- a/db/rpc/export.go +++ /dev/null @@ -1,58 +0,0 @@ -package rpc - -import ( - "errors" - "net" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "mongo.games.com/goserver/core/logger" - - "mongo.games.com/game/db/proto/user" - "mongo.games.com/game/db/rpc/server" - "mongo.games.com/game/db/rpc/svc" -) - -// GrpcServer grpc服务 -var GrpcServer *grpc.Server - -// GrpcClientConn grpc客户端连接 -var GrpcClientConn *grpc.ClientConn - -// RunGrpcServer 启动grpc服务端 -func RunGrpcServer(addr string) { - GrpcServer = grpc.NewServer() - registerGrpcServer() - ln, err := net.Listen("tcp", addr) - if err != nil { - panic(errors.New("db grpc failed to listen: " + err.Error())) - } - - err = GrpcServer.Serve(ln) - if err != nil { - panic(errors.New("db grpc failed to serve: " + err.Error())) - } - logger.Logger.Infof("db grpc start success") -} - -// NewGrpcClientConn 创建grpc客户端连接 -func NewGrpcClientConn(addr string) { - var err error - GrpcClientConn, err = grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - panic(errors.New("db grpc failed to dial: " + err.Error())) - } - registerGrpcClient() -} - -// registerGrpcServer 注册grpc服务 -func registerGrpcServer() { - ctx := svc.NewServiceContext() - user.RegisterUserServerServer(GrpcServer, server.NewUserServer(ctx)) -} - -var UserClient user.UserServerClient - -func registerGrpcClient() { - UserClient = user.NewUserServerClient(GrpcClientConn) -} diff --git a/db/rpc/logic/userlogic.go b/db/rpc/logic/userlogic.go deleted file mode 100644 index 492f7cc..0000000 --- a/db/rpc/logic/userlogic.go +++ /dev/null @@ -1,34 +0,0 @@ -package logic - -import ( - "context" - - "mongo.games.com/game/db/dao" - "mongo.games.com/game/db/model" - "mongo.games.com/game/db/proto/user" - "mongo.games.com/game/db/rpc/svc" -) - -type UserLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext -} - -func NewUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLogic { - return &UserLogic{ - ctx: ctx, - svcCtx: svcCtx, - } -} - -func (l *UserLogic) Save(in *user.SaveReq) (*user.SaveRsp, error) { - u, err := svc.GetUserCollection(in.GetPlatform(), model.User{}, dao.NewUser) - if err != nil { - return nil, err - } - _, err = u.InsertOne(l.ctx, &model.User{}) - if err != nil { - return nil, err - } - return &user.SaveRsp{}, nil -} diff --git a/db/rpc/server/userserver.go b/db/rpc/server/userserver.go deleted file mode 100644 index 6f953c1..0000000 --- a/db/rpc/server/userserver.go +++ /dev/null @@ -1,29 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -// goctl 1.7.2 -// Source: user.proto - -package server - -import ( - "context" - - "mongo.games.com/game/db/proto/user" - "mongo.games.com/game/db/rpc/logic" - "mongo.games.com/game/db/rpc/svc" -) - -type UserServer struct { - svcCtx *svc.ServiceContext - user.UnimplementedUserServerServer -} - -func NewUserServer(svcCtx *svc.ServiceContext) *UserServer { - return &UserServer{ - svcCtx: svcCtx, - } -} - -func (s *UserServer) Save(ctx context.Context, in *user.SaveReq) (*user.SaveRsp, error) { - l := logic.NewUserLogic(ctx, s.svcCtx) - return l.Save(in) -} diff --git a/db/rpc/svc/servicecontext.go b/db/rpc/svc/servicecontext.go deleted file mode 100644 index 7f11e8c..0000000 --- a/db/rpc/svc/servicecontext.go +++ /dev/null @@ -1,97 +0,0 @@ -package svc - -import ( - "fmt" - "reflect" - "strings" - - "go.mongodb.org/mongo-driver/mongo" - - mon "mongo.games.com/game/mongo" - "mongo.games.com/game/util/viperx" - "mongo.games.com/goserver/core/logger" -) - -// ServiceContext 服务上下文 -// 依赖注入 -type ServiceContext struct { -} - -func NewServiceContext() *ServiceContext { - - vp := viperx.GetViper("mgo", "json") - // mongo初始化 - conf := &mon.Config{} - err := vp.Unmarshal(conf) - if err != nil { - panic(fmt.Errorf("mongo config error: %v", err)) - } - mon.Init(conf) - - return &ServiceContext{} -} - -type TableName interface { - TableName() string -} - -// GetTableName 获取表名 -func GetTableName(model any) string { - if m, ok := model.(TableName); ok { - return m.TableName() - } - - t := reflect.TypeOf(model) - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - if t.Kind() != reflect.Struct { - panic("model must be a struct or a pointer to a struct") - } - - return strings.ToLower(t.Name()) -} - -// GetUserCollection 用户库 -func GetUserCollection[T any](platform string, model any, f func(database *mongo.Database, c *mongo.Collection) T) (T, error) { - c, err := mon.GetUserCollection(platform, GetTableName(model)) - if err != nil { - var z T - logger.Logger.Errorf("GetUserCollection error: %v", err) - return z, err - } - return f(c.Database.Database, c.Collection), nil -} - -// GetLogCollection 日志库 -func GetLogCollection[T any](platform string, model any, f func(database *mongo.Database, c *mongo.Collection) T) (T, error) { - c, err := mon.GetLogCollection(platform, GetTableName(model)) - if err != nil { - var z T - logger.Logger.Errorf("GetLogCollection error: %v", err) - return z, err - } - return f(c.Database.Database, c.Collection), nil -} - -// GetGlobalUserCollection 全局用户库 -func GetGlobalUserCollection[T any](model any, f func(database *mongo.Database, c *mongo.Collection) T) (T, error) { - c, err := mon.GetGlobalUserCollection(GetTableName(model)) - if err != nil { - var z T - logger.Logger.Errorf("GetGlobalUserCollection error: %v", err) - return z, err - } - return f(c.Database.Database, c.Collection), nil -} - -// GetGlobalLogCollection 全局日志库 -func GetGlobalLogCollection[T any](model any, f func(database *mongo.Database, c *mongo.Collection) T) (T, error) { - c, err := mon.GetGlobalLogCollection(GetTableName(model)) - if err != nil { - var z T - logger.Logger.Errorf("GetGlobalLogCollection error: %v", err) - return z, err - } - return f(c.Database.Database, c.Collection), nil -} diff --git a/gamesrv/base/player.go b/gamesrv/base/player.go index 5aea1b3..53d263d 100644 --- a/gamesrv/base/player.go +++ b/gamesrv/base/player.go @@ -640,8 +640,8 @@ func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, gamingTime := int32(time.Now().Sub(this.scene.GameNowTime).Seconds()) mq.Write(model.CreatePlayerGameRecEvent(this.SnId, tax, taxex, changeCoin, validbet, validFlow, in, out, - int32(this.scene.GameId), this.scene.GetGameFreeId(), int32(this.scene.GameMode), - this.scene.GetRecordId(), this.Channel, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, + this.scene.GameId, this.scene.GetGameFreeId(), int32(this.scene.GameMode), + this.scene.GetRecordId(), this.Channel, this.ChannelId, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, this.CreateTime, gamingTime, gameFirstTime, gameFreeFirstTime, gameTimes, gameFreeTimes, this.LastLoginTime, this.TelephonePromoter, this.DeviceId), mq.BackGameRecord) } diff --git a/go.mod b/go.mod index 70fd5d8..e040bc4 100644 --- a/go.mod +++ b/go.mod @@ -18,10 +18,8 @@ require ( github.com/howeyc/fsnotify v0.9.0 github.com/idealeak/goserver v0.0.0-20201014040547-b8f686262078 github.com/jinzhu/now v1.1.5 - github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/mojocn/base64Captcha v1.3.6 - github.com/sirupsen/logrus v1.9.0 github.com/spf13/cast v1.7.0 github.com/spf13/viper v1.19.0 github.com/tealeg/xlsx v1.0.5 @@ -63,6 +61,7 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/klauspost/reedsolomon v1.12.4 // indirect + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/lestrrat-go/strftime v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -76,6 +75,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect diff --git a/go.sum b/go.sum index ab41286..79422ec 100644 --- a/go.sum +++ b/go.sum @@ -168,8 +168,9 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -296,8 +297,8 @@ github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKz github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= diff --git a/model/dataevent.go b/model/dataevent.go index 12b2d9c..3cb9070 100644 --- a/model/dataevent.go +++ b/model/dataevent.go @@ -1,8 +1,6 @@ package model import ( - "encoding/json" - "strconv" "time" "github.com/jinzhu/now" @@ -90,30 +88,30 @@ type LuckyDiceGameNoteData struct { } // 在线统计 -type PlayerOnlineEvent struct { - Online map[int]int - Time time.Time -} - -func MarshalPlayerOnlineEvent(source int32, online map[string]int) (data string, err error) { - m := map[int]int{} - for k, v := range online { - i, _ := strconv.Atoi(k) - m[i] = v - } - raw := &RabbitMQDataRaw{ - Source: source, - Data: &PlayerOnlineEvent{ - Online: m, - Time: time.Now(), - }, - } - d, err := json.Marshal(raw) - if err != nil { - return - } - return string(d), nil -} +//type PlayerOnlineEvent struct { +// Online map[int]int +// Time time.Time +//} +// +//func MarshalPlayerOnlineEvent(source int32, online map[string]int) (data string, err error) { +// m := map[int]int{} +// for k, v := range online { +// i, _ := strconv.Atoi(k) +// m[i] = v +// } +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &PlayerOnlineEvent{ +// Online: m, +// Time: time.Now(), +// }, +// } +// d, err := json.Marshal(raw) +// if err != nil { +// return +// } +// return string(d), nil +//} // 玩家登录 type PlayerLoginEvent struct { @@ -166,34 +164,34 @@ func CreatePlayerLoginEvent(snid int32, channel, promoter, platform, city, os, i } // 用户升级账号 -type PlayerBindPhoneEvent struct { - SnId int32 //用户ID - Channel string //渠道 - Promoter string //推广 - Platform string //平台 - City string //城市 - OS string //操作系统 - Value int32 //占位用 - TelephonePromoter int32 //电销 - CreateTime int64 //创建日期 - BindTime int64 //绑定日期 -} - -func CreatePlayerBindPhoneEvent(snid int32, channel, promoter, platform, city, os string, - createTime time.Time, telephonePromoter int32) *PlayerBindPhoneEvent { - return &PlayerBindPhoneEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - TelephonePromoter: telephonePromoter, - Platform: platform, - City: city, - OS: os, - Value: 1, - CreateTime: createTime.Unix(), - BindTime: time.Now().Unix(), - } -} +//type PlayerBindPhoneEvent struct { +// SnId int32 //用户ID +// Channel string //渠道 +// Promoter string //推广 +// Platform string //平台 +// City string //城市 +// OS string //操作系统 +// Value int32 //占位用 +// TelephonePromoter int32 //电销 +// CreateTime int64 //创建日期 +// BindTime int64 //绑定日期 +//} +// +//func CreatePlayerBindPhoneEvent(snid int32, channel, promoter, platform, city, os string, +// createTime time.Time, telephonePromoter int32) *PlayerBindPhoneEvent { +// return &PlayerBindPhoneEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// TelephonePromoter: telephonePromoter, +// Platform: platform, +// City: city, +// OS: os, +// Value: 1, +// CreateTime: createTime.Unix(), +// BindTime: time.Now().Unix(), +// } +//} //func MarshalPlayerBindPhoneEvent(source, snid int32, channel, promoter, platform, city, os string, // createTime time.Time, telephonePromoter int32) (data string, err error) { @@ -210,46 +208,46 @@ func CreatePlayerBindPhoneEvent(snid int32, channel, promoter, platform, city, o //} // 用户升级账号 -type PlayerBindAlipayEvent struct { - SnId int32 //用户ID - Channel string //渠道 - Promoter string //推广 - TelephonePromoter int32 //电销 - Platform string //平台 - City string //城市 - OS string //操作系统 - Value int32 //占位用 - BindTime int64 //绑定日期 -} - -func MarshalPlayerBindAlipayEvent(source, snid int32, channel, promoter, platform, city, os string, telephonePromoter int32) (data string, err error) { - raw := &RabbitMQDataRaw{ - Source: source, - Data: &PlayerBindAlipayEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - Platform: platform, - TelephonePromoter: telephonePromoter, - City: city, - OS: os, - Value: 1, - BindTime: time.Now().Local().Unix(), - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} +//type PlayerBindAlipayEvent struct { +// SnId int32 //用户ID +// Channel string //渠道 +// Promoter string //推广 +// TelephonePromoter int32 //电销 +// Platform string //平台 +// City string //城市 +// OS string //操作系统 +// Value int32 //占位用 +// BindTime int64 //绑定日期 +//} +// +//func MarshalPlayerBindAlipayEvent(source, snid int32, channel, promoter, platform, city, os string, telephonePromoter int32) (data string, err error) { +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &PlayerBindAlipayEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// Platform: platform, +// TelephonePromoter: telephonePromoter, +// City: city, +// OS: os, +// Value: 1, +// BindTime: time.Now().Local().Unix(), +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} // 玩家游戏记录 type PlayerGameRecEvent struct { RecordId string //游戏记录ID SnId int32 //用户ID - Channel string //渠道 + Channel string //包类型 Promoter string //推广 Platform string //平台 City string //城市 @@ -258,26 +256,26 @@ type PlayerGameRecEvent struct { GameId int32 //游戏id ModeId int32 //游戏模式 Tax int64 //税收 - //Taxex int64 //税收2 - Amount int64 //金币变化(正值为赢;负值为输) - CreateTime int64 //创建时间 - CreateDayTime int64 //账号创建时间0点 - ValidBet int64 //有效下注数量 - ValidFlow int64 //有效流水数量 - Out int64 //产出 - In int64 //投入 - IsNew int32 //是否是新人 - GameFreeID int32 //游戏freeid - GamingTime int32 //游戏开始到玩家结算的时长 单位:秒 - FirstTime int64 //首次玩该场次游戏时间 - PlayTimes int64 //该场次游戏次数 - FirstGameTime int64 //首次玩游戏时间 - PlayGameTimes int64 //该游戏总次数 - LastLoginTime int64 //最后登录时间 - DeviceId string //设备id + Amount int64 //金币变化(正值为赢;负值为输) + CreateTime int64 //创建时间 + CreateDayTime int64 //账号创建时间0点 + ValidBet int64 //有效下注数量 + ValidFlow int64 //有效流水数量 + Out int64 //产出 + In int64 //投入 + IsNew int32 //是否是新人 + GameFreeID int32 //游戏freeid + GamingTime int32 //游戏开始到玩家结算的时长 单位:秒 + FirstTime int64 //首次玩该场次游戏时间 + PlayTimes int64 //该场次游戏次数 + FirstGameTime int64 //首次玩游戏时间 + PlayGameTimes int64 //该游戏总次数 + LastLoginTime int64 //最后登录时间 + DeviceId string //设备id + ChannelId string //推广渠道id } -func CreatePlayerGameRecEvent(snid int32, tax, taxex, amount, validbet, validflow, in, out int64, gameid, gameFreeId, modeid int32, recordId, channel, promoter, +func CreatePlayerGameRecEvent(snid int32, tax, taxex, amount, validbet, validflow, in, out int64, gameid, gameFreeId, modeid int32, recordId, channel, channelId, promoter, platform, city, os string, createDayTime time.Time, gamingTime int32, firstGameFreeTime, firstGameTime time.Time, playGameFreeTimes, playerGameTimes int64, lastLoginTime time.Time, teleponePromoter int32, deviceId string) *PlayerGameRecEvent { isNewbie := int32(0) @@ -315,242 +313,227 @@ func CreatePlayerGameRecEvent(snid int32, tax, taxex, amount, validbet, validflo PlayTimes: playGameFreeTimes, PlayGameTimes: playerGameTimes, LastLoginTime: lastLoginTime.Unix(), - DeviceId: deviceId} -} - -func MarshalPlayerGameRecEvent(source, snid int32, tax, taxex, amount, validbet, validflow, in, out int64, gameid, gameFreeId, modeid int32, recordId, channel, promoter, - platform, city, os string, createDayTime time.Time, gamingTime int32, firstGameFreeTime time.Time, - playGameFreeTimes int64, lastLoginTime time.Time, telephonePromoter int32, firstGameTime time.Time, - playGameTimes int64, deviceId string) (data string, err error) { - raw := &RabbitMQDataRaw{ - Source: source, - Data: CreatePlayerGameRecEvent(snid, tax, taxex, amount, validbet, validflow, in, out, gameid, gameFreeId, modeid, recordId, channel, promoter, - platform, city, os, createDayTime, gamingTime, firstGameFreeTime, firstGameTime, playGameFreeTimes, playGameTimes, lastLoginTime, telephonePromoter, deviceId), + DeviceId: deviceId, + ChannelId: channelId, } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return } // 玩家游戏记录 -type PlayerGameRecPayEvent struct { - SnId int32 //用户ID - Channel string //渠道 - Promoter string //推广 - Platform string //平台 - City string //城市 - OS string //操作系统 - TelephonePromoter int32 //电销标签 - IsNew int32 //是否新人 - IsPay int32 //是否付费 - IsGame int32 //是否游戏 - CreateTime int64 //记录创建时间 - CreateDayTime int64 //记录创建时间0点 - Time int64 //当前时间 - RegisterDayTime int64 //玩家注册时间 -} - -func MarshalPlayerGameRecPayEvent(source, snid, isPay, isGame int32, channel, promoter, platform, city, os string, - createDayTime time.Time, orderCreateTime int64, telephonePromoter int32) (data string, err error) { - isNewbie := int32(0) - if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { - isNewbie = 1 - } - tNow := time.Now() - raw := &RabbitMQDataRaw{ - Source: source, - Data: &PlayerGameRecPayEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - Platform: platform, - City: city, - OS: os, - IsNew: isNewbie, - TelephonePromoter: telephonePromoter, - IsPay: isPay, - IsGame: isGame, - RegisterDayTime: createDayTime.Local().Unix(), - CreateTime: time.Unix(orderCreateTime, 0).Local().Unix(), - CreateDayTime: now.New(time.Unix(orderCreateTime, 0)).BeginningOfDay().Local().Unix(), - Time: tNow.Local().Unix(), - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} - -// 破产统计 -type BankruptcyEvent struct { - SnId int32 //用户id - Channel string //渠道 - Promoter string //推广 - Platform string //平台 - City string //城市 - Value int32 //值 - TelephonePromoter int32 //电销标签 - IsNew int32 //是否新人 - Time int64 //操作时间 - GameId int32 //游戏id - GameMode int32 //游戏模式id - GameFreeId int32 //游戏场次id -} - -func MarshalBankruptcyEvent(source, snid, telephonePromoter int32, channel, promoter, platform, city string, createDayTime time.Time, gameId, gameMode, gameFreeId int32) (data string, err error) { - isNewbie := int32(0) - if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { - isNewbie = 1 - } - raw := &RabbitMQDataRaw{ - Source: source, - Data: &BankruptcyEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - TelephonePromoter: telephonePromoter, - Platform: platform, - City: city, - IsNew: isNewbie, - Value: 0, - Time: time.Now().Local().Unix(), - GameId: gameId, - GameMode: gameMode, - GameFreeId: gameFreeId, - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} - -// 充值统计 -type PlayerPayEvent struct { - SnId int32 //用户id - Channel string //渠道 - Promoter string //推广 - Platform string //平台 - City string //城市 - TelephonePromoter int32 //电销标记 - Tag int32 //#充值类型 0 API直接充值 1在线充值 - BeforeCoin int32 //充值前钱包数量 - BeforeBank int32 //充值前保险柜数量 - Amount int32 //充值金额 - IsNew int32 //是否是新人 - Time int64 //操作时间 -} - -func MarshalPlayerPayEvent(source, snid, tag, beforeCoin, beforeBank, amount int32, channel, - promoter, platform, city string, createDayTime time.Time, orderCreateTime int64, - telephonePromoter int32) (data string, err error) { - isNewbie := int32(0) - if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { - isNewbie = 1 - } - raw := &RabbitMQDataRaw{ - Source: source, - Data: &PlayerPayEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - Platform: platform, - City: city, - Tag: tag, - TelephonePromoter: telephonePromoter, - BeforeCoin: beforeCoin, - BeforeBank: beforeBank, - Amount: amount, - IsNew: isNewbie, - Time: time.Unix(orderCreateTime, 0).Local().Unix(), - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} - -// 系统赠送 -type SystemGiveEvent struct { - SnId int32 //用户id - Channel string //渠道 - Promoter string //推广 - Platform string //平台 - City string //城市 - TelephonePromoter int32 //电销 - Tag int32 //#充值类型 0 API直接充值 1在线充值 - Amount int32 //充值金额 - Time int64 //操作时间 -} - -func MarshalSystemGiveEvent(source, snid, tag, amount int32, channel, promoter, platform, city string, - telephonePromoter int32) (data string, err error) { - raw := &RabbitMQDataRaw{ - Source: source, - Data: &SystemGiveEvent{ - SnId: snid, - Channel: channel, - Promoter: promoter, - Platform: platform, - TelephonePromoter: telephonePromoter, - City: city, - Tag: tag, - Amount: amount, - Time: time.Now().Local().Unix(), - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} - -// 水池变化记录 -type GameCoinPoolEvent struct { - Platform string //平台 - GameId int32 //游戏id - GroupId int32 //组id - ChangeCoin int64 //变化金币 - CurCoin int64 //变化后金币 - UpCoin int64 //上限 - DownCoin int64 //下限 - Time int64 //操作时间 -} - -func MarshalGameCoinPoolEvent(source int32, platform string, gameid, groupId int32, changeCoin, - curCoin, upCoin, downCoin int64) (data string, err error) { - - raw := &RabbitMQDataRaw{ - Source: source, - Data: &GameCoinPoolEvent{ - Platform: platform, - GameId: gameid, - - GroupId: groupId, - ChangeCoin: changeCoin, - CurCoin: curCoin, - UpCoin: upCoin, - DownCoin: downCoin, - Time: time.Now().Local().Unix(), - }, - } - d, e := json.Marshal(raw) - if e == nil { - data = string(d[:]) - } - err = e - return -} +//type PlayerGameRecPayEvent struct { +// SnId int32 //用户ID +// Channel string //渠道 +// Promoter string //推广 +// Platform string //平台 +// City string //城市 +// OS string //操作系统 +// TelephonePromoter int32 //电销标签 +// IsNew int32 //是否新人 +// IsPay int32 //是否付费 +// IsGame int32 //是否游戏 +// CreateTime int64 //记录创建时间 +// CreateDayTime int64 //记录创建时间0点 +// Time int64 //当前时间 +// RegisterDayTime int64 //玩家注册时间 +//} +// +//func MarshalPlayerGameRecPayEvent(source, snid, isPay, isGame int32, channel, promoter, platform, city, os string, +// createDayTime time.Time, orderCreateTime int64, telephonePromoter int32) (data string, err error) { +// isNewbie := int32(0) +// if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { +// isNewbie = 1 +// } +// tNow := time.Now() +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &PlayerGameRecPayEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// Platform: platform, +// City: city, +// OS: os, +// IsNew: isNewbie, +// TelephonePromoter: telephonePromoter, +// IsPay: isPay, +// IsGame: isGame, +// RegisterDayTime: createDayTime.Local().Unix(), +// CreateTime: time.Unix(orderCreateTime, 0).Local().Unix(), +// CreateDayTime: now.New(time.Unix(orderCreateTime, 0)).BeginningOfDay().Local().Unix(), +// Time: tNow.Local().Unix(), +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} +// +//// 破产统计 +//type BankruptcyEvent struct { +// SnId int32 //用户id +// Channel string //渠道 +// Promoter string //推广 +// Platform string //平台 +// City string //城市 +// Value int32 //值 +// TelephonePromoter int32 //电销标签 +// IsNew int32 //是否新人 +// Time int64 //操作时间 +// GameId int32 //游戏id +// GameMode int32 //游戏模式id +// GameFreeId int32 //游戏场次id +//} +// +//func MarshalBankruptcyEvent(source, snid, telephonePromoter int32, channel, promoter, platform, city string, createDayTime time.Time, gameId, gameMode, gameFreeId int32) (data string, err error) { +// isNewbie := int32(0) +// if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { +// isNewbie = 1 +// } +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &BankruptcyEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// TelephonePromoter: telephonePromoter, +// Platform: platform, +// City: city, +// IsNew: isNewbie, +// Value: 0, +// Time: time.Now().Local().Unix(), +// GameId: gameId, +// GameMode: gameMode, +// GameFreeId: gameFreeId, +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} +// +//// 充值统计 +//type PlayerPayEvent struct { +// SnId int32 //用户id +// Channel string //渠道 +// Promoter string //推广 +// Platform string //平台 +// City string //城市 +// TelephonePromoter int32 //电销标记 +// Tag int32 //#充值类型 0 API直接充值 1在线充值 +// BeforeCoin int32 //充值前钱包数量 +// BeforeBank int32 //充值前保险柜数量 +// Amount int32 //充值金额 +// IsNew int32 //是否是新人 +// Time int64 //操作时间 +//} +// +//func MarshalPlayerPayEvent(source, snid, tag, beforeCoin, beforeBank, amount int32, channel, +// promoter, platform, city string, createDayTime time.Time, orderCreateTime int64, +// telephonePromoter int32) (data string, err error) { +// isNewbie := int32(0) +// if now.BeginningOfDay().Equal(now.New(createDayTime).BeginningOfDay()) { +// isNewbie = 1 +// } +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &PlayerPayEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// Platform: platform, +// City: city, +// Tag: tag, +// TelephonePromoter: telephonePromoter, +// BeforeCoin: beforeCoin, +// BeforeBank: beforeBank, +// Amount: amount, +// IsNew: isNewbie, +// Time: time.Unix(orderCreateTime, 0).Local().Unix(), +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} +// +//// 系统赠送 +//type SystemGiveEvent struct { +// SnId int32 //用户id +// Channel string //渠道 +// Promoter string //推广 +// Platform string //平台 +// City string //城市 +// TelephonePromoter int32 //电销 +// Tag int32 //#充值类型 0 API直接充值 1在线充值 +// Amount int32 //充值金额 +// Time int64 //操作时间 +//} +// +//func MarshalSystemGiveEvent(source, snid, tag, amount int32, channel, promoter, platform, city string, +// telephonePromoter int32) (data string, err error) { +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &SystemGiveEvent{ +// SnId: snid, +// Channel: channel, +// Promoter: promoter, +// Platform: platform, +// TelephonePromoter: telephonePromoter, +// City: city, +// Tag: tag, +// Amount: amount, +// Time: time.Now().Local().Unix(), +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} +// +//// 水池变化记录 +//type GameCoinPoolEvent struct { +// Platform string //平台 +// GameId int32 //游戏id +// GroupId int32 //组id +// ChangeCoin int64 //变化金币 +// CurCoin int64 //变化后金币 +// UpCoin int64 //上限 +// DownCoin int64 //下限 +// Time int64 //操作时间 +//} +// +//func MarshalGameCoinPoolEvent(source int32, platform string, gameid, groupId int32, changeCoin, +// curCoin, upCoin, downCoin int64) (data string, err error) { +// +// raw := &RabbitMQDataRaw{ +// Source: source, +// Data: &GameCoinPoolEvent{ +// Platform: platform, +// GameId: gameid, +// +// GroupId: groupId, +// ChangeCoin: changeCoin, +// CurCoin: curCoin, +// UpCoin: upCoin, +// DownCoin: downCoin, +// Time: time.Now().Local().Unix(), +// }, +// } +// d, e := json.Marshal(raw) +// if e == nil { +// data = string(d[:]) +// } +// err = e +// return +//} diff --git a/mongo/export.go b/mongo/export.go deleted file mode 100644 index a86a949..0000000 --- a/mongo/export.go +++ /dev/null @@ -1,145 +0,0 @@ -package mongo - -import ( - "errors" - - "go.mongodb.org/mongo-driver/mongo" - "mongo.games.com/goserver/core/logger" - - "mongo.games.com/game/mongo/internal" -) - -type DatabaseType string - -const ( - KeyGlobal = "global" - DatabaseUser DatabaseType = "user" - DatabaseLog DatabaseType = "log" -) - -var NotInitError = errors.New("mongo manager is nil, please call Init() first") - -type Config = internal.Config -type DatabaseConfig = internal.DatabaseConfig -type Collection = internal.Collection -type Database = internal.Database - -var _manager *internal.Manager - -// GetConfig 获取配置 -func GetConfig() *Config { - if _manager == nil { - return nil - } - return _manager.GetConfig() -} - -// Init 初始化 -func Init(conf *Config) { - _manager = internal.NewManager(conf) -} - -// Restart 重启 -func Restart() { - if _manager == nil { - logger.Logger.Error(NotInitError) - return - } - _manager.Restart(_manager.GetConfig()) -} - -// Close 关闭 -func Close() { - internal.Close(_manager) -} - -// GetDatabase 获取数据库 -// platform: 平台id -// database: 数据库名称 -func GetDatabase(platform string, database DatabaseType) (*Database, error) { - if _manager == nil { - return nil, NotInitError - } - - return _manager.GetDatabase(platform, string(database)) -} - -func GetUserDatabase(platform string) (*Database, error) { - return GetDatabase(platform, DatabaseUser) -} - -func GetLogDatabase(platform string) (*Database, error) { - return GetDatabase(platform, DatabaseLog) -} - -// GetGlobalDatabase 获取全局库 -// database: 数据库名称 -func GetGlobalDatabase(database DatabaseType) (*Database, error) { - if _manager == nil { - return nil, NotInitError - } - - return _manager.GetDatabase(KeyGlobal, string(database)) -} - -func GetGlobalUserDatabase() (*Database, error) { - return GetGlobalDatabase(DatabaseUser) -} - -func GetGlobalLogDatabase() (*Database, error) { - return GetGlobalDatabase(DatabaseLog) -} - -// GetGlobalCollection 获取全局库 -// database: 数据库名称 -// collection: 集合名称 -func GetGlobalCollection(database DatabaseType, collection string) (*Collection, error) { - if _manager == nil { - return nil, NotInitError - } - - return _manager.GetCollection(KeyGlobal, string(database), collection) -} - -func GetGlobalUserCollection(collection string) (*Collection, error) { - return GetGlobalCollection(DatabaseUser, collection) -} - -func GetGlobalLogCollection(collection string) (*Collection, error) { - return GetGlobalCollection(DatabaseLog, collection) -} - -// GetCollection 获取平台库 -// platform: 平台id -// database: 数据库名称 -// collection: 集合名称 -func GetCollection(platform string, database DatabaseType, collection string) (*Collection, error) { - if _manager == nil { - return nil, NotInitError - } - - return _manager.GetCollection(platform, string(database), collection) -} - -func GetUserCollection(platform string, collection string) (*Collection, error) { - return GetCollection(platform, DatabaseUser, collection) -} - -func GetLogCollection(platform string, collection string) (*Collection, error) { - return GetCollection(platform, DatabaseLog, collection) -} - -// GetClient 获取数据库连接 -// 默认获取的是 Global, log 的数据库连接 -func GetClient() (*mongo.Client, error) { - if _manager == nil { - return nil, NotInitError - } - - c, err := _manager.GetCollection(KeyGlobal, string(DatabaseLog), "empty") - if err != nil { - return nil, err - } - - return c.Database.Client, nil -} diff --git a/mongo/internal/mongo.go b/mongo/internal/mongo.go deleted file mode 100644 index 9d54b9c..0000000 --- a/mongo/internal/mongo.go +++ /dev/null @@ -1,196 +0,0 @@ -package internal - -import ( - "context" - "fmt" - "sync" - "time" - - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "mongo.games.com/goserver/core/logger" -) - -type Config struct { - Global map[string]*DatabaseConfig - Platforms map[string]map[string]*DatabaseConfig -} - -type DatabaseConfig struct { - HostName string // 主机地址 - HostPort int32 // 端口 - Database string // 数据库名 - Username string // 用户名 - Password string // 密码 - Options string // 配置 -} - -type Collection struct { - Database *Database - *mongo.Collection -} - -type Database struct { - *DatabaseConfig - Client *mongo.Client - Database *mongo.Database - Collection sync.Map -} - -func (d *Database) Connect() error { - if d.DatabaseConfig == nil { - err := fmt.Errorf("mongo Connect error, DatabaseConifg not found") - logger.Logger.Error(err) - return err - } - - login := "" - if d.DatabaseConfig.Username != "" { - login = d.DatabaseConfig.Username + ":" + d.DatabaseConfig.Password + "@" - } - host := d.DatabaseConfig.HostName - if d.DatabaseConfig.HostName == "" { - host = "127.0.0.1" - } - port := d.DatabaseConfig.HostPort - if d.DatabaseConfig.HostPort == 0 { - port = 27017 - } - myOptions := d.DatabaseConfig.Options - if myOptions != "" { - myOptions = "?" + myOptions - } - - s := fmt.Sprintf("mongodb://%s%s:%d/admin%s", login, host, port, myOptions) - client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(s)) - if err != nil { - logger.Logger.Errorf("mongo Connect %v error: %v config:%+v", s, err, *d.DatabaseConfig) - return err - } - logger.Logger.Tracef("mongo connect success %+v", *d.DatabaseConfig) - d.Client = client - d.Database = client.Database(d.DatabaseConfig.Database) - return nil -} - -func (d *Database) GetCollection(name string) (*Collection, error) { - if d.Database == nil { - err := fmt.Errorf("mongo GetCollection error, collection:%v, database is nil", name) - logger.Logger.Error(err) - return nil, err - } - v, ok := d.Collection.Load(name) - if !ok { - v = &Collection{ - Database: d, - Collection: d.Database.Collection(name), - } - d.Collection.Store(name, v) - } - c, _ := v.(*Collection) - return c, nil -} - -type Manager struct { - conf *Config - global *sync.Map // 内部库名称:Database - platforms *sync.Map // 平台id:内部库名称:Database -} - -func (m *Manager) GetCollection(key, database, collection string) (*Collection, error) { - d, err := m.GetDatabase(key, database) - if err != nil { - return nil, err - } - return d.GetCollection(collection) -} - -func (m *Manager) GetDatabase(key, database string) (*Database, error) { - switch key { - case "global": - v, ok := m.global.Load(database) - if !ok { - db := &Database{ - DatabaseConfig: m.conf.Global[database], - Collection: sync.Map{}, - } - if err := db.Connect(); err != nil { - return nil, err - } - v = db - m.global.Store(database, v) - } - d, _ := v.(*Database) - return d, nil - - default: - var mp *sync.Map - v, ok := m.platforms.Load(key) // 平台id - if !ok { - mp = new(sync.Map) - m.platforms.Store(key, mp) - } else { - mp = v.(*sync.Map) - } - v, ok = mp.Load(database) - if !ok { - db := &Database{ - DatabaseConfig: m.conf.Platforms[key][database], - Collection: sync.Map{}, - } - if err := db.Connect(); err != nil { - return nil, err - } - v = db - mp.Store(database, v) - } - d, _ := v.(*Database) - return d, nil - } -} - -func (m *Manager) Restart(conf *Config) { - logger.Logger.Infof("mongo manager restart...") - old := *m - time.AfterFunc(time.Minute, func() { - Close(&old) - }) - - m.conf = conf - m.global = &sync.Map{} - m.platforms = &sync.Map{} -} - -func Close(m *Manager) { - logger.Logger.Infof("mongo manager close") - m.global.Range(func(key, value any) bool { - if v, ok := value.(*Database); ok { - v.Client.Disconnect(nil) - } - return true - }) - - m.platforms.Range(func(key, value any) bool { - if v, ok := value.(*sync.Map); ok { - v.Range(func(key, value any) bool { - if v, ok := value.(*Database); ok { - v.Client.Disconnect(nil) - } - return true - }) - } - return true - }) -} - -func (m *Manager) GetConfig() *Config { - return m.conf -} - -func NewManager(conf *Config) *Manager { - return &Manager{ - conf: conf, - global: &sync.Map{}, - platforms: &sync.Map{}, - } -} diff --git a/statistics/.gitignore b/statistics/.gitignore deleted file mode 100644 index 43aacb1..0000000 --- a/statistics/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# ---> Go -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work - -.idea -.vscode -log - diff --git a/statistics/README.md b/statistics/README.md deleted file mode 100644 index 88cdc2b..0000000 --- a/statistics/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# statistics - -数据分析服务 - - * 定时查询注册表和登录日志获取玩家id,根据玩家id触发相关的数据统计 - -- [x] 新手离开记录 -- [ ] 在线时长 \ No newline at end of file diff --git a/statistics/build_linux.bat b/statistics/build_linux.bat deleted file mode 100644 index 7962122..0000000 --- a/statistics/build_linux.bat +++ /dev/null @@ -1,8 +0,0 @@ -set GOPATH=D:\godev -go env -w GO111MODULE=on - -set CGO_ENABLED=0 -set GOOS=linux -set GOARCH=amd64 -go build -pause \ No newline at end of file diff --git a/statistics/constant/constant.go b/statistics/constant/constant.go deleted file mode 100644 index bf3f798..0000000 --- a/statistics/constant/constant.go +++ /dev/null @@ -1,13 +0,0 @@ -package constant - -const ( - User = "user" // 用户库内部名称 - Log = "log" // 日志库内部名称 -) - -const ( - InviteScoreTypeBind = 1 // 绑定邀请码 - InviteScoreTypePay = 2 // 充值返佣 - InviteScoreTypeRecharge = 3 // 充值完成 - InviteScoreTypePayMe = 4 // 充值(自己) -) diff --git a/statistics/etc/config.yaml b/statistics/etc/config.yaml deleted file mode 100644 index ba82d5c..0000000 --- a/statistics/etc/config.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# 平台id -platforms: - - 1 - -# 几秒同步一次数据 -# 注册表,登录日志表 -update_second: 60 -# 注册表每次同步多少条数据 -update_account_num: 100 -# 登录日志每次同步多少条数据 -update_login_num: 100 -# 几秒读取一次玩家id列表 -update_second_snid: 30 -# 最多触发几个玩家数据更新 -update_snid_num: 100 - -# 邀请数据统计 -# 几秒读取一次邀请记录 -update_second_invite: 10 -# 一次最多读取多少条邀请记录 -update_invite_num: 30 - -# 道具获得数量统计 -# 几秒读取一次道具日志 -update_second_item: 10 -# 一次最多读取多少道具日志 -update_item_num: 100 \ No newline at end of file diff --git a/statistics/etc/mongo.yaml b/statistics/etc/mongo.yaml deleted file mode 100644 index 7f9e42d..0000000 --- a/statistics/etc/mongo.yaml +++ /dev/null @@ -1,53 +0,0 @@ -global: - user: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_global - Username: - Password: - Options: - log: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_log - Username: - Password: - Options: - monitor: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_monitor - Username: - Password: - Options: -platforms: - 0: - user: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_user_plt_000 - Username: - Password: - Options: - log: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_log_plt_000 - Username: - Password: - Options: - 1: - user: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_user_plt_001 - Username: - Password: - Options: - log: - HostName: 127.0.0.1 - HostPort: 27017 - Database: win88_log_plt_001 - Username: - Password: - Options: \ No newline at end of file diff --git a/statistics/etc/mysql.yaml b/statistics/etc/mysql.yaml deleted file mode 100644 index b639fbf..0000000 --- a/statistics/etc/mysql.yaml +++ /dev/null @@ -1,31 +0,0 @@ -platforms: - global: - HostName: 127.0.0.1 - HostPort: 3306 - Database: win88_user - Username: root - Password: 123456 - Options: charset=utf8mb4&parseTime=True&loc=Local - 0: - HostName: 127.0.0.1 - HostPort: 3306 - Database: win88_plt_000 - Username: root - Password: 123456 - Options: charset=utf8mb4&parseTime=True&loc=Local - 1: - HostName: 127.0.0.1 - HostPort: 3306 - Database: win88_plt_001 - Username: root - Password: 123456 - Options: charset=utf8mb4&parseTime=True&loc=Local - -# 最大空闲连接数 -MaxIdleConns: 10 -# 最大连接数 -MaxOpenConns: 100 -# 连接可复用的最大时间 -ConnMaxLifetime: 3600 -# 连接最大空闲时间 -ConnMaxIdletime: 0 \ No newline at end of file diff --git a/statistics/local_test.go b/statistics/local_test.go deleted file mode 100644 index 9e66fc5..0000000 --- a/statistics/local_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "context" - "fmt" - "testing" - "time" -) - -type A struct { -} - -func B() *A { - return nil -} - -func Test1(t *testing.T) { - var a interface{} - a = B() - fmt.Println(a == nil) // false -} - -func Test2(t *testing.T) { - c1 := context.Background() - c2, cancel2 := context.WithCancel(c1) - c3, _ := context.WithCancel(c2) - - go func() { - select { - case <-c3.Done(): - fmt.Println("c3 cancel") - } - }() - - time.Sleep(time.Second * 5) - cancel2() - fmt.Println("cancel2") - - //time.Sleep(time.Second * 5) - //cancel3() - //fmt.Println("cancel3") - - time.Sleep(time.Minute) -} - -func Test3(t *testing.T) { - n := time.Now() - y, m, d := n.Date() - n = time.Date(y, m, d, 0, 0, 0, 0, time.Local) - st := n.AddDate(0, 0, -int(n.Weekday())) - et := n.AddDate(0, 0, 7-int(n.Weekday())) - fmt.Println(st, et) -} diff --git a/statistics/logger.xml b/statistics/logger.xml deleted file mode 100644 index f6eb37b..0000000 --- a/statistics/logger.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/statistics/main.go b/statistics/main.go deleted file mode 100644 index dd5e27d..0000000 --- a/statistics/main.go +++ /dev/null @@ -1,239 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "sync" - "time" - - "github.com/spf13/viper" - "mongo.games.com/goserver/core/logger" - - "mongo.games.com/game/mongo" - "mongo.games.com/game/mysql" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" - "mongo.games.com/game/statistics/static" - "mongo.games.com/game/statistics/syn" - "mongo.games.com/game/statistics/tools" - "mongo.games.com/game/util/viperx" -) - -var VP *viper.Viper - -//func init() { -// // 日志 -// *log.StandardLogger() = *log.New() -// -// // 日志等级 -// level, err := log.ParseLevel(VP.GetString("log.level")) -// if err != nil { -// panic(err) -// } -// log.SetLevel(level) -// -// // 打印文件路径及行号 -// log.AddHook(tools.NewFileLineHook(log.ErrorLevel)) -// -// // 日志切分 -// for _, v := range VP.Get("log.rotate").([]interface{}) { -// conf := &tools.RotateLogConfig{} -// b, err := json.Marshal(v) -// if err != nil { -// panic(err) -// } -// if err = json.Unmarshal(b, conf); err != nil { -// panic(err) -// } -// log.AddHook(tools.NewRotateLogHook(conf)) -// } -//} - -// DoTick 定时执行 -func DoTick(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, fu func(ctx context.Context)) { - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case <-ctx.Done(): - return - case <-time.After(duration): - tools.RecoverPanicFunc() // 捕获异常 - fu(ctx) - } - } - }() -} - -func DoTickPlatform(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, batchSize int, - fu func(ctx context.Context, platform string, batchSize int)) { - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case <-ctx.Done(): - return - case <-time.After(duration): - tools.RecoverPanicFunc() // 捕获异常 - wg := new(sync.WaitGroup) - for _, v := range VP.GetStringSlice("platforms") { - platform := v - wg.Add(1) - go func() { - defer wg.Done() - fu(ctx, platform, batchSize) - }() - } - wg.Wait() - } - } - }() -} - -func main() { - VP = viperx.GetViper("config", "yaml") - // mongo - vp := viperx.GetViper("mongo", "yaml") - // mongo初始化 - conf := &mongo.Config{} - err := vp.Unmarshal(conf) - if err != nil { - panic(fmt.Errorf("mongo config error: %v", err)) - } - mongo.Init(conf) - defer mongo.Close() - - // mysql - vp = viperx.GetViper("mysql", "yaml") - myConf := &mysql.Config{} - err = vp.Unmarshal(myConf) - if err != nil { - panic(fmt.Errorf("mysql config error: %v", err)) - } - mysql.Init(myConf) - defer mysql.Close() - - mysql.SetAutoMigrateTables(mysqlmodel.Tables) - - wg := &sync.WaitGroup{} - ctx, cancel := context.WithCancel(context.Background()) - - DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second"))*time.Second, SyncSnId) - - DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_snid"))*time.Second, func(ctx context.Context) { - wg := new(sync.WaitGroup) - for _, v := range VP.GetStringSlice("platforms") { - platform := v - wg.Add(1) - go func() { - defer wg.Done() - Static(platform) - }() - } - wg.Wait() - }) - - DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_invite"))*time.Second, SyncInvite) - - DoTickPlatform(ctx, wg, time.Duration(VP.GetInt64("update_second_item"))*time.Second, VP.GetInt("update_item_num"), - func(ctx context.Context, platform string, batchSize int) { - err := syn.ItemGainDone(&syn.Data[mongomodel.ItemLog]{ - Platform: platform, - BatchSize: batchSize, - }) - if err != nil { - logger.Logger.Errorf("SyncItem error:%v", err) - } - }) - - logger.Logger.Info("start") - - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt, os.Kill) - sig := <-c - logger.Logger.Infof("closing down (signal: %v)", sig) - - // release - cancel() - wg.Wait() - - logger.Logger.Info("closed") -} - -// SyncSnId 同步注册和登录日志 -func SyncSnId(ctx context.Context) { - wg := new(sync.WaitGroup) - for _, v := range VP.GetStringSlice("platforms") { - platform := v - wg.Add(1) - go func() { - defer wg.Done() - _, err := syn.UserAccount(platform, VP.GetInt("update_account_num")) - if err != nil { - logger.Logger.Errorf("SyncUserAccount error: %v", err) - return - } - - _, err = syn.LogLogin(platform, VP.GetInt("update_login_num")) - if err != nil { - logger.Logger.Errorf("SyncLogLogin error: %v", err) - return - } - }() - } - wg.Wait() -} - -// Static 玩家id触发数据统计 -func Static(platform string) { - // 查询需要更新的玩家id - var ids []*mysqlmodel.UserID - db, err := mysql.GetDatabase(platform) - if err != nil { - logger.Logger.Errorf("GetDatabase error: %v", err) - return - } - if err := db.Limit(VP.GetInt("update_snid_num")).Find(&ids).Error; err != nil { - logger.Logger.Warnf("Get UserID error: %v", err) - return - } - - if len(ids) == 0 { - logger.Logger.Tracef("Static: no need to update") - return - } - - // 统计玩家跳出记录 - if err := static.UserLogin(platform, ids); err != nil { - logger.Logger.Errorf("StaticUserLogin error: %v", err) - return - } - - // 删除更新过的玩家id - if err := db.Delete(ids).Error; err != nil { - logger.Logger.Errorf("Delete error: %v", err) - return - } -} - -// SyncInvite 同步邀请数据 -func SyncInvite(ctx context.Context) { - wg := new(sync.WaitGroup) - for _, v := range VP.GetStringSlice("platforms") { - platform := v - wg.Add(1) - go func() { - defer wg.Done() - err := syn.SyncInviteScore(platform, VP.GetInt("update_invite_num")) - if err != nil { - logger.Logger.Errorf("SyncInviteScore error: %v", err) - return - } - }() - } - wg.Wait() -} diff --git a/statistics/mongo/model/log_gameplayerlistlog.go b/statistics/mongo/model/log_gameplayerlistlog.go deleted file mode 100644 index 4eeac20..0000000 --- a/statistics/mongo/model/log_gameplayerlistlog.go +++ /dev/null @@ -1,47 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -const LogGamePlayerListLog = "log_gameplayerlistlog" - -type GamePlayerListLog struct { - LogId primitive.ObjectID `bson:"_id"` - SnId int32 //用户Id - Name string //名称 - GameId int32 //游戏id - BaseScore int32 //游戏底注 - ClubId int32 //俱乐部Id - ClubRoom string //俱乐部包间 - TaxCoin int64 //税收 - ClubPumpCoin int64 //俱乐部额外抽水 - Platform string //平台id - Channel string //渠道 - Promoter string //推广员 - PackageTag string //包标识 - SceneId int32 //场景ID - GameMode int32 //游戏类型 - GameFreeid int32 //游戏类型房间号 - GameDetailedLogId string //游戏记录Id - IsFirstGame bool //是否第一次游戏 - //对于拉霸类:BetAmount=100 WinAmountNoAnyTax=0 (表示投入多少、收益多少,值>=0) - //拉霸类小游戏会是:BetAmount=0 WinAmountNoAnyTax=100 (投入0、收益多少,值>=0) - //对战场:BetAmount=0 WinAmountNoAnyTax=100 (投入会有是0、收益有正负,WinAmountNoAnyTax=100则盈利,WinAmountNoAnyTax=-100则输100) - BetAmount int64 //下注金额 - WinAmountNoAnyTax int64 //盈利金额,不包含任何税 - TotalIn int64 //本局投入 - TotalOut int64 //本局产出 - Time time.Time //记录时间 - RoomType int32 //房间类型 - GameDif string //游戏标识 - GameClass int32 //游戏类型 1棋牌 2电子 3百人 4捕鱼 5视讯 6彩票 7体育 - MatchId int32 - MatchType int32 //0.普通场 1.锦标赛 2.冠军赛 3.vip专属 - Ts int32 - IsFree bool //拉霸专用 是否免费 - WinSmallGame int64 //拉霸专用 小游戏奖励 - WinTotal int64 //拉霸专用 输赢 -} diff --git a/statistics/mongo/model/log_invitescore.go b/statistics/mongo/model/log_invitescore.go deleted file mode 100644 index 4e6253c..0000000 --- a/statistics/mongo/model/log_invitescore.go +++ /dev/null @@ -1,19 +0,0 @@ -package model - -import ( - "go.mongodb.org/mongo-driver/bson/primitive" -) - -const LogInviteScore = "log_invitescore" - -type InviteScore struct { - Id primitive.ObjectID `bson:"_id"` - UpSnid int // 上级代理 - DownSnid int // 下级代理 - Level int // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 - Tp int // 返佣类型 - Rate int // 返佣比例 - Score int // 积分 - Money int // 充值金额 - Ts int // 时间戳 -} diff --git a/statistics/mongo/model/log_item.go b/statistics/mongo/model/log_item.go deleted file mode 100644 index 0c6bf87..0000000 --- a/statistics/mongo/model/log_item.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -import "go.mongodb.org/mongo-driver/bson/primitive" - -const LogItem = "log_itemlog" - -type ItemInfo struct { - ItemId int32 - ItemNum int64 -} - -type ItemLog struct { - LogId primitive.ObjectID `bson:"_id"` - Platform string //平台 - SnId int32 //玩家id - LogType int32 //记录类型 0.获取 1.消耗 - ItemId int32 //道具id - ItemName string //道具名称 - Count int64 //个数 - CreateTs int64 //记录时间 - Remark string //备注 - TypeId int32 // 变化类型 - GameId int32 // 游戏id,游戏中获得时有值 - GameFreeId int32 // 场次id,游戏中获得时有值 - Cost []*ItemInfo // 消耗的道具 - Id string // 撤销的id,兑换失败 -} diff --git a/statistics/mongo/model/log_login.go b/statistics/mongo/model/log_login.go deleted file mode 100644 index 7394d3e..0000000 --- a/statistics/mongo/model/log_login.go +++ /dev/null @@ -1,33 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -const LogLogin = "log_login" - -const ( - LogTypeLogin int32 = iota // 登录 - LogTypeLogout // 登出 - LogTypeRehold // 重连 - LogTypeDrop // 掉线 -) - -type LoginLog struct { - LogId primitive.ObjectID `bson:"_id"` - Platform string //平台id - SnId int32 - LogType int32 - Ts int64 - Time time.Time - GameId int // 玩家掉线时所在游戏id - LastGameID int // 玩家最后所在游戏id - ChannelId string // 推广渠道 - - DeviceName string - AppVersion string - BuildVersion string - AppChannel string -} diff --git a/statistics/mongo/model/user_account.go b/statistics/mongo/model/user_account.go deleted file mode 100644 index f87bc7d..0000000 --- a/statistics/mongo/model/user_account.go +++ /dev/null @@ -1,24 +0,0 @@ -package model - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -const UserAccount = "user_account" - -type Account struct { - AccountId primitive.ObjectID `bson:"_id"` - SnId int32 // 玩家账号直接在这里生成 - Platform string // 平台 - RegisterTs int64 // 注册时间戳 - RegisteTime time.Time - ChannelId string // 推广渠道 - - Tel string `gorm:"index"` - DeviceName string `gorm:"index"` - AppVersion string `gorm:"index"` - BuildVersion string `gorm:"index"` - AppChannel string `gorm:"index"` -} diff --git a/statistics/mysql/model/init.go b/statistics/mysql/model/init.go deleted file mode 100644 index 976ac05..0000000 --- a/statistics/mysql/model/init.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// 需要自动迁移的表添加在这里 Tables - -var Tables = []interface{}{ - &LogLogin{}, - &LogLoginMid{}, - &UserAccount{}, - &UserLogin{}, - &UserID{}, - &LogInviteScoreMid{}, - &LogInviteScore{}, - &LogInviteUser{}, - &LogMid{}, - &ItemGain{}, - &ItemTotalGain{}, -} diff --git a/statistics/mysql/model/log_invitescore.go b/statistics/mysql/model/log_invitescore.go deleted file mode 100644 index 177d219..0000000 --- a/statistics/mysql/model/log_invitescore.go +++ /dev/null @@ -1,26 +0,0 @@ -package model - -type LogInviteScoreMid struct { - ID uint `gorm:"primaryKey"` - MID string -} - -type LogInviteScore struct { - ID uint `gorm:"primaryKey"` - UpSnid int `gorm:"index"` // 上级代理 - DownSnid int `gorm:"index"` // 下级代理 - Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 - Tp int `gorm:"index"` // 返佣类型 - Rate int `gorm:"index"` // 返佣比例 - Score int `gorm:"index"` // 积分 - Money int `gorm:"index"` // 充值金额 - Ts int `gorm:"index"` // 时间戳 -} - -type LogInviteUser struct { - ID uint `gorm:"primaryKey"` - Psnid int `gorm:"index"` // 当前玩家 - Snid int `gorm:"index"` // 一级代理 - Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 - Ts int `gorm:"index"` // 绑定时间 -} diff --git a/statistics/mysql/model/log_itemgain.go b/statistics/mysql/model/log_itemgain.go deleted file mode 100644 index b361104..0000000 --- a/statistics/mysql/model/log_itemgain.go +++ /dev/null @@ -1,16 +0,0 @@ -package model - -// ItemGain 道具获得数量,以小时,道具id,做主键 -type ItemGain struct { - ID uint `gorm:"primaryKey"` - Hour int64 `gorm:"index:idx_item"` // 小时时间戳,每小时统计一次 - ItemId int32 `gorm:"index:idx_item"` // 道具id - ItemNum int64 // 道具数量 -} - -// ItemTotalGain 道具获得总数 -type ItemTotalGain struct { - ID uint `gorm:"primaryKey"` - ItemId int32 `gorm:"index"` // 道具id - ItemNum int64 // 道具数量 -} diff --git a/statistics/mysql/model/log_login.go b/statistics/mysql/model/log_login.go deleted file mode 100644 index 3d1aea4..0000000 --- a/statistics/mysql/model/log_login.go +++ /dev/null @@ -1,26 +0,0 @@ -package model - -import "time" - -const ( - LogTypeLogin = 1 // 登录 - LogTypeRehold = 2 // 重连 - LogTypeOffline = 3 // 离线 -) - -type LogLogin struct { - ID uint `gorm:"primaryKey"` - Snid int `gorm:"index"` - OnlineType int `gorm:"index"` - //OnlineTs int `gorm:"index"` - OnlineTime time.Time `gorm:"index"` - OfflineType int `gorm:"index"` - //OfflineTs int `gorm:"index"` - OfflineTime time.Time `gorm:"index"` - ChannelId string `gorm:"index"` // 推广渠道 - - DeviceName string `gorm:"index"` - AppVersion string `gorm:"index"` - BuildVersion string `gorm:"index"` - AppChannel string `gorm:"index"` -} diff --git a/statistics/mysql/model/log_login_mid.go b/statistics/mysql/model/log_login_mid.go deleted file mode 100644 index d46df2e..0000000 --- a/statistics/mysql/model/log_login_mid.go +++ /dev/null @@ -1,6 +0,0 @@ -package model - -type LogLoginMid struct { - ID uint `gorm:"primaryKey"` - MID string -} diff --git a/statistics/mysql/model/log_mid.go b/statistics/mysql/model/log_mid.go deleted file mode 100644 index 047c56c..0000000 --- a/statistics/mysql/model/log_mid.go +++ /dev/null @@ -1,11 +0,0 @@ -package model - -const ( - MidTypeItem = 1 // 道具记录 -) - -type LogMid struct { - ID uint `gorm:"primaryKey"` - Tp int `gorm:"index"` // 类型 - MID string -} diff --git a/statistics/mysql/model/user_account.go b/statistics/mysql/model/user_account.go deleted file mode 100644 index d0c61d1..0000000 --- a/statistics/mysql/model/user_account.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -import "time" - -type UserAccount struct { - ID uint `gorm:"primaryKey"` - MID string - Snid int `gorm:"index"` - //RegisterTs int `gorm:"index"` - RegisterTime time.Time `gorm:"index"` - ChannelId string `gorm:"index"` // 推广渠道 - - DeviceName string `gorm:"index"` - AppVersion string `gorm:"index"` - BuildVersion string `gorm:"index"` - AppChannel string `gorm:"index"` - Tel string `gorm:"index"` -} diff --git a/statistics/mysql/model/user_id.go b/statistics/mysql/model/user_id.go deleted file mode 100644 index a8c2360..0000000 --- a/statistics/mysql/model/user_id.go +++ /dev/null @@ -1,9 +0,0 @@ -package model - -/* - 服务定期查询注册和登录信息,然后获取玩家id,保存到这张表中;用于后续触发和玩家相关的数据统计 -*/ - -type UserID struct { - Snid int `gorm:"primaryKey"` -} diff --git a/statistics/mysql/model/user_login.go b/statistics/mysql/model/user_login.go deleted file mode 100644 index a5235e2..0000000 --- a/statistics/mysql/model/user_login.go +++ /dev/null @@ -1,29 +0,0 @@ -package model - -import "time" - -const ( - OutTypRegister = 1 // 注册 - OutTypeLogin = 2 // 登录 - OutTypeGaming = 3 // 游戏中 - OutTypeGameOver = 4 // 游戏结束 -) - -type UserLogin struct { - ID uint `gorm:"primaryKey"` - Snid int `gorm:"uniqueIndex"` - //OnlineTs int `gorm:"index"` - OnlineTime time.Time `gorm:"index"` - //OfflineTs int `gorm:"index"` - OfflineTime time.Time `gorm:"index"` - OutType int `gorm:"index"` // 跳出类型 - GameID int `gorm:"index"` // 游戏id - Age int - Sex int - DeviceName string `gorm:"index"` - AppVersion string `gorm:"index"` - BuildVersion string `gorm:"index"` - AppChannel string `gorm:"index"` - Tel string `gorm:"index"` - ChannelId string `gorm:"index"` // 推广渠道 -} diff --git a/statistics/shell/close.sh b/statistics/shell/close.sh deleted file mode 100644 index 47f55d7..0000000 --- a/statistics/shell/close.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -pkill -2 statistics -echo "close ..." -tail -f log/all_log \ No newline at end of file diff --git a/statistics/shell/start.sh b/statistics/shell/start.sh deleted file mode 100644 index 980d151..0000000 --- a/statistics/shell/start.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -nohup ./statistics > /dev/null & diff --git a/statistics/static/init.go b/statistics/static/init.go deleted file mode 100644 index 4a9e036..0000000 --- a/statistics/static/init.go +++ /dev/null @@ -1 +0,0 @@ -package static diff --git a/statistics/static/user_login.go b/statistics/static/user_login.go deleted file mode 100644 index ca7f8a8..0000000 --- a/statistics/static/user_login.go +++ /dev/null @@ -1,372 +0,0 @@ -package static - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "mongo.games.com/goserver/core/logger" - - mymongo "mongo.games.com/game/mongo" - mymysql "mongo.games.com/game/mysql" - - "mongo.games.com/game/statistics/constant" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" -) - -func getAccountTel(platform string, id int) (string, error) { - acc := &mongomodel.Account{} - cc, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.User, mongomodel.UserAccount, err) - return "", err - } - dd := cc.FindOne(context.TODO(), bson.M{"snid": id}, options.FindOne().SetProjection(bson.M{"tel": 1})) - err = dd.Err() - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Tracef("getAccountTel %v not found in user_account", id) - return "", nil - } - logger.Logger.Errorf("getAccountTel %v get user_account err: %v", id, err) - return "", err - } - if err := dd.Decode(acc); err != nil { - logger.Logger.Errorf("getAccountTel %v decode user_account err: %v", id, err) - return "", err - } - return acc.Tel, nil -} - -// 游戏结束离开 -func checkGameOver(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { - // 最早的一条掉线记录并且是游戏结束离开 - a := &mongomodel.LoginLog{} - c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) - return false, err - } - d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": 0, "lastgameid": bson.D{{"$gt", 0}}}, - options.FindOne().SetSort(bson.D{{"time", 1}})) - err = d.Err() - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Tracef("checkGameOver %v not found in log_login", id) - return false, nil - } - logger.Logger.Errorf("checkGameOver %v get log_login err: %v", id, err) - return false, err - } - if err := d.Decode(a); err != nil { - logger.Logger.Errorf("checkGameOver %v decode log_login err: %v", id, err) - return false, err - } - - // account tel - tel, err := getAccountTel(platform, id) - if err != nil { - logger.Logger.Warnf("get account tel %v err: %v", id, err) - } - - update := &mysqlmodel.UserLogin{ - //OfflineTs: int(a.Ts), - OfflineTime: a.Time, - OutType: mysqlmodel.OutTypeGameOver, - GameID: a.LastGameID, - Tel: tel, - DeviceName: a.DeviceName, - AppVersion: a.AppVersion, - BuildVersion: a.BuildVersion, - AppChannel: a.AppChannel, - ChannelId: a.ChannelId, - } - - if err := db.Model(login).Select( - "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", - ).Updates(update).Error; err != nil { - logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) - return false, err - } - - return true, nil -} - -// 游戏中离开 -func checkGaming(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { - // 最早的一条掉线记录并且是游戏中掉线 - a := &mongomodel.LoginLog{} - c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) - return false, err - } - d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": bson.D{{"$gt", 0}}}, - options.FindOne().SetSort(bson.D{{"time", 1}})) - err = d.Err() - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Tracef("checkGaming %v not found in log_login", id) - return false, nil - } - logger.Logger.Errorf("checkGaming %v get log_login err: %v", id, err) - return false, err - } - if err := d.Decode(a); err != nil { - logger.Logger.Errorf("checkGaming %v decode log_login err: %v", id, err) - return false, err - } - - // account tel - tel, err := getAccountTel(platform, id) - if err != nil { - logger.Logger.Warnf("get account tel %v err: %v", id, err) - } - - update := &mysqlmodel.UserLogin{ - //OfflineTs: int(a.Ts), - OfflineTime: a.Time, - OutType: mysqlmodel.OutTypeGaming, - GameID: a.GameId, - Tel: tel, - DeviceName: a.DeviceName, - AppVersion: a.AppVersion, - BuildVersion: a.BuildVersion, - AppChannel: a.AppChannel, - ChannelId: a.ChannelId, - } - - if err := db.Model(login).Select( - "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", - ).Updates(update).Error; err != nil { - logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) - return false, err - } - - return true, nil -} - -// 登录后离开 -func checkLogin(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { - // 最早的一条掉线记录 - a := &mongomodel.LoginLog{} - c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) - return false, err - } - d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop}, options.FindOne().SetSort(bson.D{{"time", 1}})) - err = d.Err() - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Tracef("checkLogin %v not found in log_login", id) - return false, nil - } - logger.Logger.Errorf("checkLogin %v get log_login err: %v", id, err) - return false, err - } - if err := d.Decode(a); err != nil { - logger.Logger.Errorf("checkLogin %v decode log_login err: %v", id, err) - return false, err - } - - // account tel - tel, err := getAccountTel(platform, id) - if err != nil { - logger.Logger.Warnf("get account tel %v err: %v", id, err) - } - - update := &mysqlmodel.UserLogin{ - //OfflineTs: int(a.Ts), - OfflineTime: a.Time, - OutType: mysqlmodel.OutTypeLogin, - Tel: tel, - DeviceName: a.DeviceName, - AppVersion: a.AppVersion, - BuildVersion: a.BuildVersion, - AppChannel: a.AppChannel, - ChannelId: a.ChannelId, - } - - if err := db.Model(login).Select( - "OfflineTime", "OutType", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", - ).Updates(update).Error; err != nil { - logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) - return false, err - } - - return true, nil -} - -// 注册后离开 -func checkRegister(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { - a := &mongomodel.Account{} - c, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.UserAccount, err) - return false, err - } - d := c.FindOne(context.TODO(), bson.M{"snid": id}) - err = d.Err() - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Warnf("checkRegister %v not found in user_account", id) - return false, nil - } - logger.Logger.Errorf("checkRegister %v get user_account err: %v", id, err) - return false, err - } - if err := d.Decode(a); err != nil { - logger.Logger.Errorf("checkRegister %v decode user_account err: %v", id, err) - return false, err - } - - // account tel - tel, err := getAccountTel(platform, id) - if err != nil { - logger.Logger.Warnf("get account tel %v err: %v", id, err) - } - - login.Snid = id - //login.OnlineTs = int(a.RegisterTs) - login.OnlineTime = a.RegisteTime - //login.OfflineTs = int(a.RegisterTs) - login.OfflineTime = a.RegisteTime - login.OutType = mysqlmodel.OutTypRegister - login.Tel = tel - login.DeviceName = a.DeviceName - login.AppVersion = a.AppVersion - login.BuildVersion = a.BuildVersion - login.AppChannel = a.AppChannel - login.ChannelId = a.ChannelId - - if err := db.Create(login).Error; err != nil { - logger.Logger.Errorf("checkRegister create err: %v", err) - return false, err - } - return true, nil -} - -// UserLogin 玩家跳出统计 -func UserLogin(platform string, ids []*mysqlmodel.UserID) error { - f := func(id int) error { - // 玩家是否已经统计结束,已经是游戏结束状态 - login := &mysqlmodel.UserLogin{} - db, err := mymysql.GetDatabase(platform) - if err != nil { - logger.Logger.Errorf("UserLogin get db err: %v", err) - return err - } - if err = db.Where("snid = ?", id).Find(login).Error; err != nil { - logger.Logger.Errorf("UserLogin find %v err: %v", id, err) - return err - } - - switch login.OutType { - case mysqlmodel.OutTypeGameOver: - return nil - - case mysqlmodel.OutTypeGaming: - _, err := checkGameOver(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) - return err - } - return nil - - case mysqlmodel.OutTypeLogin: - ret, err := checkGameOver(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) - return err - } - if ret { - return nil - } - ret, err = checkGaming(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) - return err - } - if ret { - return nil - } - - case mysqlmodel.OutTypRegister: - ret, err := checkGameOver(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) - return err - } - if ret { - return nil - } - ret, err = checkGaming(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) - return err - } - if ret { - return nil - } - ret, err = checkLogin(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) - return err - } - if ret { - return nil - } - - default: - ret, err := checkRegister(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkRegister %v err: %v", id, err) - return err - } - if !ret { - logger.Logger.Warnf("UserLogin not found user_account checkRegister %v err: %v", id, err) - return nil - } - - ret, err = checkGameOver(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) - return err - } - if ret { - return nil - } - ret, err = checkGaming(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) - return err - } - if ret { - return nil - } - ret, err = checkLogin(db, login, platform, id) - if err != nil { - logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) - return err - } - if ret { - return nil - } - return nil - } - - return nil - } - - for _, v := range ids { - if err := f(v.Snid); err != nil { - return err - } - } - - return nil -} diff --git a/statistics/syn/init.go b/statistics/syn/init.go deleted file mode 100644 index b7247af..0000000 --- a/statistics/syn/init.go +++ /dev/null @@ -1,102 +0,0 @@ -package syn - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm" - - mymongo "mongo.games.com/game/mongo" - mymysql "mongo.games.com/game/mysql" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" - "mongo.games.com/goserver/core/logger" -) - -// Data 数据同步方法 -// T mongodb数据表结构 -// F mongodb中的每条数据的处理操作,自行实现 -type Data[T any] struct { - Platform string // 平台 - MidType int // 数据类型 例如 model.MidTypeItem - Database string // 库名称 - CollectionName string // 集合名称 - BatchSize int // 一次读取数量 - // F 自定义数据处理方法 - // data: mongodb中的一条日志 - F func(data *T, db *gorm.DB) (string, error) -} - -// CommonDone 数据获取方式,根据mongodb集合主键按时间顺序批量读取 -func (d *Data[T]) CommonDone() error { - db, err := mymysql.GetDatabase(d.Platform) - if err != nil { - logger.Logger.Errorf("mysql: failed to get database: %v", err) - return err - } - loginMID := &mysqlmodel.LogMid{Tp: d.MidType} - var n int64 - err = db.Model(&mysqlmodel.LogMid{}).Find(loginMID).Count(&n).Error - if err != nil { - logger.Logger.Errorf("mysql: failed to get log_mid: %v", err) - return err - } - if n == 0 { - if err = db.Create(loginMID).Error; err != nil { - logger.Logger.Errorf("mysql: failed to create log_mid: %v", err) - return err - } - } - - logger.Logger.Tracef("start log_mid tp:%v _id:%v", loginMID.Tp, loginMID.MID) - - _id, _ := primitive.ObjectIDFromHex(loginMID.MID) - filter := bson.M{"_id": bson.M{"$gt": _id}} - c, err := mymongo.GetCollection(d.Platform, mymongo.DatabaseType(d.Database), d.CollectionName) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", d.Database, d.CollectionName, err) - return err - } - l, err := c.Find(context.TODO(), filter, - options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(d.BatchSize))) - if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) - return err - } - - var logs []*T - if err = l.All(context.TODO(), &logs); err != nil { - l.Close(context.TODO()) - if errors.Is(err, mongo.ErrNoDocuments) { - return nil - } - - logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) - return err - } - l.Close(context.TODO()) - if len(logs) == 0 { - logger.Logger.Infof("sync %v finished", d.CollectionName) - return nil - } - - err = db.Transaction(func(tx *gorm.DB) error { - for _, v := range logs { - loginMID.MID, err = d.F(v, tx) - if err != nil { - logger.Logger.Errorf("Process %v error:%v", d.CollectionName, err) - return err - } - if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { - logger.Logger.Errorf("mysql: failed to update %v log_mid: %v", d.CollectionName, err) - return err - } - } - return nil - }) - - return err -} diff --git a/statistics/syn/log_invitescore.go b/statistics/syn/log_invitescore.go deleted file mode 100644 index fa17b14..0000000 --- a/statistics/syn/log_invitescore.go +++ /dev/null @@ -1,291 +0,0 @@ -package syn - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm" - - mymongo "mongo.games.com/game/mongo" - mymysql "mongo.games.com/game/mysql" - "mongo.games.com/game/statistics/constant" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" - "mongo.games.com/goserver/core/logger" -) - -func SyncInviteScore(platform string, batchSize int) error { - db, err := mymysql.GetDatabase(platform) - if err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to get database: %v", err) - return err - } - inviteMID := &mysqlmodel.LogInviteScoreMid{ID: 1} - var n int64 - err = db.Model(&mysqlmodel.LogInviteScoreMid{}).Find(inviteMID).Count(&n).Error - if err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to get log_invitescore_mid: %v", err) - return err - } - if n == 0 { - if err = db.Create(inviteMID).Error; err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invitescore_mid: %v", err) - return err - } - } - - logger.Logger.Tracef("start SyncInviteScore log_invitescore _id:%v", inviteMID.MID) - - _id, _ := primitive.ObjectIDFromHex(inviteMID.MID) - filter := bson.M{"_id": bson.M{"$gt": _id}} - c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogInviteScore) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogInviteScore, err) - return err - } - l, err := c.Find(context.TODO(), filter, - options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) - if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) - return err - } - - var logs []*mongomodel.InviteScore - if err = l.All(context.TODO(), &logs); err != nil { - l.Close(context.TODO()) - if errors.Is(err, mongo.ErrNoDocuments) { - return err - } - - logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) - return err - } - l.Close(context.TODO()) - - getPSnId := func(tx *gorm.DB, snid int) (int, error) { - if snid <= 0 { - return 0, nil - } - ret := new(mysqlmodel.LogInviteUser) - if err = tx.First(ret, "snid = ? and level = 1", snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: SyncInviteScore failed to getPSnId: %v", err) - return 0, err - } - return ret.Psnid, nil - } - - getDownSnId := func(tx *gorm.DB, snid []int) ([]int, error) { - if len(snid) == 0 { - return nil, nil - } - var ret []int - var us []*mysqlmodel.LogInviteUser - if err = tx.Select("snid").Where("psnid IN ? AND level = 1", snid).Find(&us).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: SyncInviteScore failed to getDownSnId: %v", err) - return ret, err - } - for _, v := range us { - ret = append(ret, v.Snid) - } - return ret, nil - } - - bind := func(tx *gorm.DB, psnid, snid int, ts int) ([]*mysqlmodel.LogInviteUser, error) { - var lu []*mysqlmodel.LogInviteUser - var a1, a2, a3, a4, b1 int - var b2, b3, b4 []int - a4 = psnid - a3, err = getPSnId(tx, a4) - if err != nil { - return nil, err - } - a2, err = getPSnId(tx, a3) - if err != nil { - return nil, err - } - a1, err = getPSnId(tx, a2) - if err != nil { - return nil, err - } - b1 = snid - b2, err = getDownSnId(tx, []int{b1}) - if err != nil { - return nil, err - } - b3, err = getDownSnId(tx, b2) - if err != nil { - return nil, err - } - b4, err = getDownSnId(tx, b3) - if err != nil { - return nil, err - } - logger.Logger.Tracef("a1:%d, a2:%d, a3:%d, a4:%d, b1:%d, b2:%v, b3:%v, b4:%v", a1, a2, a3, a4, b1, b2, b3, b4) - if a1 > 0 { - if b1 > 0 { - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a1, - Snid: b1, - Level: 4, - Ts: ts, - }) - logger.Logger.Tracef("a1: %v %v %v", b1, 4, ts) - } - } - if a2 > 0 { - if b1 > 0 { - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a2, - Snid: b1, - Level: 3, - Ts: ts, - }) - logger.Logger.Tracef("a2: %v %v %v", b1, 3, ts) - } - for _, v := range b2 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a2, - Snid: v, - Level: 4, - Ts: ts, - }) - logger.Logger.Tracef("a2: %v %v %v", v, 4, ts) - } - } - if a3 > 0 { - if b1 > 0 { - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a3, - Snid: b1, - Level: 2, - Ts: ts, - }) - logger.Logger.Tracef("a3: %v %v %v", b1, 2, ts) - } - for _, v := range b2 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a3, - Snid: v, - Level: 3, - Ts: ts, - }) - logger.Logger.Tracef("a3: %v %v %v", v, 3, ts) - } - for _, v := range b3 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a3, - Snid: v, - Level: 4, - Ts: ts, - }) - logger.Logger.Tracef("a3: %v %v %v", v, 4, ts) - } - } - if a4 > 0 { - if b1 > 0 { - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a4, - Snid: b1, - Level: 1, - Ts: ts, - }) - logger.Logger.Tracef("a4: %v %v %v", b1, 1, ts) - } - for _, v := range b2 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a4, - Snid: v, - Level: 2, - Ts: ts, - }) - logger.Logger.Tracef("a4: %v %v %v", v, 2, ts) - } - for _, v := range b3 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a4, - Snid: v, - Level: 3, - Ts: ts, - }) - logger.Logger.Tracef("a4: %v %v %v", v, 3, ts) - } - for _, v := range b4 { - if v <= 0 { - continue - } - lu = append(lu, &mysqlmodel.LogInviteUser{ - Psnid: a4, - Snid: v, - Level: 4, - Ts: ts, - }) - logger.Logger.Tracef("a4: %v %v %v", v, 4, ts) - } - } - return lu, nil - } - - for _, v := range logs { - err = db.Transaction(func(tx *gorm.DB) error { - inviteMID.MID = v.Id.Hex() - if err = tx.Model(inviteMID).Updates(inviteMID).Error; err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to update log_invitescore_mid: %v", err) - return err - } - - err = tx.Save(&mysqlmodel.LogInviteScore{ - UpSnid: v.UpSnid, - DownSnid: v.DownSnid, - Level: v.Level, - Tp: v.Tp, - Rate: v.Rate, - Score: v.Score, - Money: v.Money, - Ts: v.Ts, - }).Error - if err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to insert: %v", err) - return err - } - - if v.Tp == constant.InviteScoreTypeBind && v.Level == 0 { - // 绑定关系 - lu, err := bind(tx, v.UpSnid, v.DownSnid, v.Ts) - if err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to bind: %v", err) - return err - } - if err = tx.CreateInBatches(lu, len(lu)).Error; err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invite_user: %v", err) - return err - } - } - - return nil - }) - if err != nil { - logger.Logger.Errorf("mysql: SyncInviteScore failed to transaction: %v", err) - return err - } - } - return nil -} diff --git a/statistics/syn/log_itemgain.go b/statistics/syn/log_itemgain.go deleted file mode 100644 index 80b828b..0000000 --- a/statistics/syn/log_itemgain.go +++ /dev/null @@ -1,61 +0,0 @@ -package syn - -import ( - "errors" - "time" - - "gorm.io/gorm" - - "mongo.games.com/game/statistics/constant" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" -) - -func ItemGainDone(data *Data[mongomodel.ItemLog]) error { - data.MidType = mysqlmodel.MidTypeItem - data.Database = constant.Log - data.CollectionName = mongomodel.LogItem - data.F = func(data *mongomodel.ItemLog, db *gorm.DB) (string, error) { - if data == nil || data.LogId.Hex() == "" { - return "", errors.New("null") - } - if data.LogType != 0 || data.Id != "" { - return data.LogId.Hex(), nil - } - - hourTime := time.Unix(data.CreateTs, 0).Local() - hourTs := time.Date(hourTime.Year(), hourTime.Month(), hourTime.Day(), hourTime.Hour(), 0, 0, 0, time.Local).Unix() - - item := &mysqlmodel.ItemGain{} - err := db.Model(item).Where("hour = ? and item_id = ?", hourTs, data.ItemId).First(item).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return "", err - } - item.Hour = hourTs - item.ItemId = data.ItemId - item.ItemNum += data.Count - if item.ID == 0 { - err = db.Create(item).Error - } else { - err = db.Model(item).Updates(item).Error - } - if err != nil { - return "", err - } - - itemTotal := &mysqlmodel.ItemTotalGain{} - err = db.Model(itemTotal).Where("item_id = ?", data.ItemId).First(itemTotal).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return "", err - } - itemTotal.ItemId = data.ItemId - itemTotal.ItemNum += data.Count - if itemTotal.ID == 0 { - err = db.Create(itemTotal).Error - } else { - err = db.Model(itemTotal).Updates(itemTotal).Error - } - return data.LogId.Hex(), err - } - return data.CommonDone() -} diff --git a/statistics/syn/log_login.go b/statistics/syn/log_login.go deleted file mode 100644 index 01260e5..0000000 --- a/statistics/syn/log_login.go +++ /dev/null @@ -1,182 +0,0 @@ -package syn - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm" - - mymongo "mongo.games.com/game/mongo" - mymysql "mongo.games.com/game/mysql" - "mongo.games.com/game/statistics/constant" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" - "mongo.games.com/goserver/core/logger" -) - -/* - 登录日志同步使用了mongo的_id,从小到大每次同步n个 -*/ - -// LogLogin 同步登录日志 -func LogLogin(platform string, batchSize int) ([]*mysqlmodel.LogLogin, error) { - db, err := mymysql.GetDatabase(platform) - if err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to get database: %v", err) - return nil, err - } - loginMID := &mysqlmodel.LogLoginMid{ID: 1} - var n int64 - err = db.Model(&mysqlmodel.LogLoginMid{}).Find(loginMID).Count(&n).Error - if err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login_mid: %v", err) - return nil, err - } - if n == 0 { - if err = db.Create(loginMID).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login_mid: %v", err) - return nil, err - } - } - - logger.Logger.Tracef("start SyncLogLogin log_login _id:%v", loginMID.MID) - - _id, _ := primitive.ObjectIDFromHex(loginMID.MID) - filter := bson.M{"_id": bson.M{"$gt": _id}} - c, err := mymongo.GetCollection(platform, constant.Log, mongomodel.LogLogin) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.LogLogin, err) - return nil, err - } - l, err := c.Find(context.TODO(), filter, - options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) - if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Errorf("mongo: SyncLogLogin failed to get log_login: %v", err) - return nil, err - } - - var logs []*mongomodel.LoginLog - if err = l.All(context.TODO(), &logs); err != nil { - l.Close(context.TODO()) - if errors.Is(err, mongo.ErrNoDocuments) { - return nil, nil - } - - logger.Logger.Errorf("mongo: SyncLogLogin failed to get loginlog: %v", err) - return nil, err - } - l.Close(context.TODO()) - - var ls []*mysqlmodel.LogLogin - for _, v := range logs { - logger.Logger.Tracef("mongo SyncLogLogin log_login: %+v", *v) - var e *mysqlmodel.LogLogin - switch v.LogType { - case mongomodel.LogTypeLogin, mongomodel.LogTypeRehold: - onlineType := mysqlmodel.LogTypeLogin - if v.LogType == mongomodel.LogTypeRehold { - onlineType = mysqlmodel.LogTypeRehold - } - - // 创建数据 - var n int64 - if err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ? AND online_type = ? AND online_time = ?", - v.SnId, onlineType, v.Time).Count(&n).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login count: %v", err) - return ls, err - } - - if n == 0 { - e = &mysqlmodel.LogLogin{ - Snid: int(v.SnId), - OnlineType: onlineType, - //OnlineTs: int(v.Ts), - OnlineTime: v.Time, - OfflineType: 0, - //OfflineTs: 0, - OfflineTime: v.Time, - DeviceName: v.DeviceName, - AppVersion: v.AppVersion, - BuildVersion: v.BuildVersion, - AppChannel: v.AppChannel, - ChannelId: v.ChannelId, - } - if err = db.Create(e).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login: %v", err) - return ls, err - } - } else { - continue - } - - case mongomodel.LogTypeLogout, mongomodel.LogTypeDrop: - // 修改数据 - e = &mysqlmodel.LogLogin{} - err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ?", v.SnId).Order("online_time DESC").First(e).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: SyncLogLogin failed to find log_login: %v", err) - return ls, err - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Warnf("mysql: SyncLogLogin not found log_login: %v", v) - continue - } - - if e.OfflineType != 0 { - logger.Logger.Tracef("mysql: SyncLogLogin already offline: %+v", *e) - continue - } - - e.OfflineType = mysqlmodel.LogTypeOffline - //e.OfflineTs = int(v.Ts) - e.OfflineTime = v.Time - if err = db.Model(e).Select("OfflineType", "OfflineTime").Updates(e).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login: %v", err) - return ls, err - } - default: - continue - } - - if e != nil { - ls = append(ls, e) - } - } - - if len(logs) > 0 { - err = db.Transaction(func(tx *gorm.DB) error { - loginMID.MID = logs[len(logs)-1].LogId.Hex() - if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login_mid: %v", err) - return err - } - - for _, v := range ls { - if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.Snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: SyncLogLogin failed to find user_id: %v", err) - return err - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - if err = tx.Create(&mysqlmodel.UserID{Snid: v.Snid}).Error; err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to create user_id: %v", err) - return err - } - } - } - - return nil - }) - if err != nil { - logger.Logger.Errorf("mysql: SyncLogLogin failed to transaction: %v", err) - return nil, err - } - } - - return ls, nil -} diff --git a/statistics/syn/user_account.go b/statistics/syn/user_account.go deleted file mode 100644 index e3f3756..0000000 --- a/statistics/syn/user_account.go +++ /dev/null @@ -1,106 +0,0 @@ -package syn - -import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - "gorm.io/gorm" - - mymongo "mongo.games.com/game/mongo" - mymysql "mongo.games.com/game/mysql" - "mongo.games.com/game/statistics/constant" - mongomodel "mongo.games.com/game/statistics/mongo/model" - mysqlmodel "mongo.games.com/game/statistics/mysql/model" - "mongo.games.com/goserver/core/logger" -) - -/* - 注册信息同步,使用mongo的_id,从小到大每次同步n个 -*/ - -// UserAccount 同步注册表 -func UserAccount(platform string, batchSize int) ([]*mysqlmodel.UserAccount, error) { - db, err := mymysql.GetDatabase(platform) - if err != nil { - logger.Logger.Errorf("mysql: UserAccount failed to get database: %v", err) - return nil, err - } - account := &mysqlmodel.UserAccount{} - err = db.Model(&mysqlmodel.UserAccount{}).Last(account).Error - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: UserAccount failed to get account: %v", err) - return nil, err - } - - logger.Logger.Tracef("start UserAccount account _id:%v", account.MID) - - _id, _ := primitive.ObjectIDFromHex(account.MID) - filter := bson.M{"_id": bson.M{"$gt": _id}} - c, err := mymongo.GetCollection(platform, constant.User, mongomodel.UserAccount) - if err != nil { - logger.Logger.Errorf("get collection %s %s error %v", constant.Log, mongomodel.UserAccount, err) - return nil, err - } - l, err := c.Find(context.TODO(), filter, - options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) - if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { - logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) - return nil, err - } - - var accounts []*mongomodel.Account - if err = l.All(context.TODO(), &accounts); err != nil { - l.Close(context.TODO()) - if errors.Is(err, mongo.ErrNoDocuments) { - return nil, nil - } - - logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) - return nil, err - } - l.Close(context.TODO()) - - var as []*mysqlmodel.UserAccount - err = db.Transaction(func(tx *gorm.DB) error { - for _, v := range accounts { - logger.Logger.Tracef("mongo account: %+v", *v) - a := &mysqlmodel.UserAccount{ - MID: v.AccountId.Hex(), - Snid: int(v.SnId), - //RegisterTs: int(v.RegisterTs), - RegisterTime: v.RegisteTime, - Tel: v.Tel, - ChannelId: v.ChannelId, - } - - if err = tx.Create(a).Error; err != nil { - logger.Logger.Errorf("mysql: UserAccount failed to create account: %v", err) - return err - } - - if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.SnId).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - logger.Logger.Errorf("mysql: UserAccount failed to find user_id: %v", err) - return err - } - - if errors.Is(err, gorm.ErrRecordNotFound) { - if err = tx.Create(&mysqlmodel.UserID{Snid: int(v.SnId)}).Error; err != nil { - logger.Logger.Errorf("mysql: UserAccount failed to create user_id: %v", err) - return err - } - } - - as = append(as, a) - } - return nil - }) - if err != nil { - logger.Logger.Errorf("mysql: UserAccount failed to transaction: %v", err) - return as, err - } - return as, nil -} diff --git a/statistics/tools/logrus_hook.go b/statistics/tools/logrus_hook.go deleted file mode 100644 index bdda57c..0000000 --- a/statistics/tools/logrus_hook.go +++ /dev/null @@ -1,95 +0,0 @@ -package tools - -import ( - "fmt" - "runtime" - "strings" - "time" - - rotatelogs "github.com/lestrrat-go/file-rotatelogs" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/writer" -) - -// FileLineHook 新增一个字段用来打印文件路径及行号 -type FileLineHook struct { - LogLevels []logrus.Level // 需要打印的日志级别 - FieldName string // 字段名称 - Skip int // 跳过几层调用栈 - Num int // Skip后的查找范围 - Test bool // 打印所有调用栈信息,找出合适的 Skip 配置 - filename string // 文件名 - line int // 行号 -} - -func (e *FileLineHook) Levels() []logrus.Level { - return e.LogLevels -} - -func (e *FileLineHook) Fire(entry *logrus.Entry) error { - for i := 0; i < e.Num; i++ { - _, e.filename, e.line, _ = runtime.Caller(e.Skip + i) - if !strings.Contains(e.filename, "logrus") { - break - } - } - entry.Data[e.FieldName] = fmt.Sprintf("%s:%d", e.filename, e.line) - if e.Test { - buf := [4096]byte{} - n := runtime.Stack(buf[:], false) - fmt.Println(string(buf[:n])) - } - return nil -} - -// NewFileLineHook 打印文件路径及行号 -// levels 指定日志级别 -func NewFileLineHook(levels ...logrus.Level) logrus.Hook { - return &FileLineHook{ - LogLevels: levels, - FieldName: "source", - Skip: 8, - Num: 2, - } -} - -type RotateLogConfig struct { - Levels []string `json:"levels"` - Pattern string `json:"pattern"` - LinkName string `json:"link_name"` - MaxAge int `json:"max_age"` - RotationTime int `json:"rotation_time"` - RotationCount int `json:"rotation_count"` - RotationSize int `json:"rotation_size"` -} - -func NewRotateLogHook(config *RotateLogConfig) logrus.Hook { - var levels []logrus.Level - for _, v := range config.Levels { - level, err := logrus.ParseLevel(v) - if err != nil { - panic(err) - } - levels = append(levels, level) - } - - if len(levels) == 0 { - levels = logrus.AllLevels - } - - l, err := rotatelogs.New(config.Pattern, - rotatelogs.WithLinkName(config.LinkName), - rotatelogs.WithMaxAge(time.Duration(config.MaxAge)*time.Hour), - rotatelogs.WithRotationTime(time.Duration(config.RotationTime)*time.Hour), - rotatelogs.WithRotationCount(uint(config.RotationCount)), - rotatelogs.WithRotationSize(int64(config.RotationSize)), - ) - if err != nil { - panic(err) - } - - return &writer.Hook{ - Writer: l, - LogLevels: levels, - } -} diff --git a/statistics/tools/panic.go b/statistics/tools/panic.go deleted file mode 100644 index b89d000..0000000 --- a/statistics/tools/panic.go +++ /dev/null @@ -1,37 +0,0 @@ -package tools - -import ( - "bytes" - "fmt" - "os" - "runtime" - "sync" -) - -var RecoverPanicFunc func(args ...interface{}) - -func init() { - bufPool := &sync.Pool{ - New: func() interface{} { - return &bytes.Buffer{} - }, - } - RecoverPanicFunc = func(args ...interface{}) { - if r := recover(); r != nil { - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - buf.WriteString(fmt.Sprintf("panic: %v\n", r)) - for _, v := range args { - buf.WriteString(fmt.Sprintf("%v\n", v)) - } - pcs := make([]uintptr, 10) - n := runtime.Callers(3, pcs) - frames := runtime.CallersFrames(pcs[:n]) - for f, again := frames.Next(); again; f, again = frames.Next() { - buf.WriteString(fmt.Sprintf("%v:%v %v\n", f.File, f.Line, f.Function)) - } - fmt.Fprint(os.Stderr, buf.String()) - } - } -} From 9906c0fb80ba60740a7854e6d9f63cfa809cd8d1 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 19 Nov 2024 10:36:22 +0800 Subject: [PATCH 23/23] no message --- util/balancequeue/queue.go | 136 -------------------------------- util/balancequeue/queue_test.go | 40 ---------- util/viperx/viper.go | 29 ------- worldsrv/dbsaver.go | 3 +- worldsrv/playercache.go | 2 +- 5 files changed, 2 insertions(+), 208 deletions(-) delete mode 100644 util/balancequeue/queue.go delete mode 100644 util/balancequeue/queue_test.go delete mode 100644 util/viperx/viper.go diff --git a/util/balancequeue/queue.go b/util/balancequeue/queue.go deleted file mode 100644 index b31465a..0000000 --- a/util/balancequeue/queue.go +++ /dev/null @@ -1,136 +0,0 @@ -package balancequeue - -import ( - "fmt" - "strings" -) - -// 平衡队列 - -type Element interface { - BalanceQueueHandler() -} - -type elementWrapper struct { - F func() -} - -func (e *elementWrapper) BalanceQueueHandler() { - e.F() -} - -func ElementWrapper(f func()) Element { - return &elementWrapper{F: f} -} - -type group struct { - Array []Element - queuePos int -} - -type groupArray struct { - queue []*group -} - -type BalanceQueue struct { - index int // 循环索引 - groups []*group // 固定的分组,长度不变,每次Update触发一个分组 - tables []*groupArray - pool map[Element]*group -} - -// New 创建一个平衡队列 -// groupNumber 分组数量 -func New(groupNumber int) *BalanceQueue { - ret := &BalanceQueue{ - groups: make([]*group, groupNumber), - tables: make([]*groupArray, 10), // 本身会自动扩容,初始值不是很重要 - pool: make(map[Element]*group), - } - - for i := 0; i < len(ret.tables); i++ { - ret.tables[i] = &groupArray{} - } - // 初始化平衡数组,所有平衡队列容量为0 - for i := 0; i < len(ret.groups); i++ { - ret.groups[i] = &group{queuePos: i} - ret.tables[0].queue = append(ret.tables[0].queue, ret.groups[i]) - } - return ret -} - -func (q *BalanceQueue) String() string { - buf := strings.Builder{} - buf.WriteString("BalanceQueue:\n") - buf.WriteString(fmt.Sprintf("分组数量: %v\n", len(q.groups))) - for k, v := range q.tables { - buf.WriteString(fmt.Sprintf("元素数量%v: 组数量%v ==>", k, len(v.queue))) - for _, vv := range v.queue { - buf.WriteString(fmt.Sprintf("%v ", len(vv.Array))) - } - buf.WriteString("\n") - } - return buf.String() -} - -func (q *BalanceQueue) Update() { - if q.index == len(q.groups) { - q.index = 0 - } - for _, v := range q.groups[q.index].Array { - v.BalanceQueueHandler() - } - q.index++ -} - -func (q *BalanceQueue) Push(e Element) { - if e == nil { - return - } - - if _, ok := q.pool[e]; ok { - return - } - - for k, v := range q.tables { - size := len(v.queue) - if size == 0 { - continue - } - - arr := v.queue[size-1] - if k+1 >= len(q.tables) { - q.tables = append(q.tables, &groupArray{}) - } - q.tables[k+1].queue = append(q.tables[k+1].queue, arr) - q.tables[k].queue = v.queue[:size-1] - arr.queuePos = len(q.tables[k+1].queue) - 1 - arr.Array = append(arr.Array, e) - q.pool[e] = arr - return - } - return -} - -func (q *BalanceQueue) Pop(e Element) { - group, ok := q.pool[e] - if !ok { - return - } - delete(q.pool, e) - count := len(group.Array) - for i := 0; i < count; i++ { - if group.Array[i] == e { - group.Array[i] = group.Array[count-1] - group.Array = group.Array[:count-1] - bqPos := group.queuePos - queCount := len(q.tables[count].queue) - q.tables[count].queue[bqPos] = q.tables[count].queue[queCount-1] - q.tables[count].queue[bqPos].queuePos = bqPos - q.tables[count].queue = q.tables[count].queue[:queCount-1] - q.tables[count-1].queue = append(q.tables[count-1].queue, group) - group.queuePos = len(q.tables[count-1].queue) - 1 - return - } - } -} diff --git a/util/balancequeue/queue_test.go b/util/balancequeue/queue_test.go deleted file mode 100644 index 927fa16..0000000 --- a/util/balancequeue/queue_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package balancequeue - -import ( - "fmt" - "math/rand" - "testing" - "time" -) - -type A struct { - Name string -} - -func (a *A) BalanceQueueHandler() { - -} - -func TestOne(t *testing.T) { - q := New(5) - - var es []Element - go func() { - for { - q.Update() - fmt.Println(q) - time.Sleep(time.Second) - e := &A{Name: fmt.Sprint(time.Now().Unix())} - es = append(es, e) - q.Push(e) - if rand.Intn(10) > 5 && len(es) >= 2 { - for _, v := range es[:2] { - q.Pop(v) - } - es = es[2:] - } - } - }() - - time.Sleep(time.Minute) -} diff --git a/util/viperx/viper.go b/util/viperx/viper.go deleted file mode 100644 index 73519eb..0000000 --- a/util/viperx/viper.go +++ /dev/null @@ -1,29 +0,0 @@ -package viperx - -import ( - "fmt" - - "github.com/spf13/viper" -) - -var paths = []string{ - ".", - "./etc", - "./config", -} - -func GetViper(name, filetype string) *viper.Viper { - vp := viper.New() - // 配置文件 - vp.SetConfigName(name) - vp.SetConfigType(filetype) - for _, v := range paths { - vp.AddConfigPath(v) - } - - err := vp.ReadInConfig() - if err != nil { - panic(fmt.Errorf("fatal error config file: %w", err)) - } - return vp -} diff --git a/worldsrv/dbsaver.go b/worldsrv/dbsaver.go index d79f3ee..4c1b056 100644 --- a/worldsrv/dbsaver.go +++ b/worldsrv/dbsaver.go @@ -3,9 +3,8 @@ package main import ( "time" + "mongo.games.com/goserver/core/container/balancequeue" "mongo.games.com/goserver/core/module" - - "mongo.games.com/game/util/balancequeue" ) var DbSaveInst = &DbSaver{ diff --git a/worldsrv/playercache.go b/worldsrv/playercache.go index 4fb0c5b..2a186d4 100644 --- a/worldsrv/playercache.go +++ b/worldsrv/playercache.go @@ -6,11 +6,11 @@ import ( "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/container/balancequeue" "mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/task" "mongo.games.com/game/model" - "mongo.games.com/game/util/balancequeue" "mongo.games.com/game/worldsrv/internal" )