game_sync/worldsrv/etcd.go

545 lines
18 KiB
Go

package main
import (
"context"
"encoding/json"
"strconv"
"strings"
"go.etcd.io/etcd/client/v3"
"mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/task"
"mongo.games.com/game/common"
"mongo.games.com/game/etcd"
"mongo.games.com/game/model"
"mongo.games.com/game/mq"
hallproto "mongo.games.com/game/protocol/gamehall"
loginproto "mongo.games.com/game/protocol/login"
playerproto "mongo.games.com/game/protocol/player"
serverproto "mongo.games.com/game/protocol/server"
"mongo.games.com/game/protocol/webapi"
"mongo.games.com/game/srvdata"
)
func init() {
// 平台配置
etcd.Register(etcd.ETCDKEY_PLATFORM_PREFIX, webapi.Platform{}, platformConfigEvent)
// 超管平台游戏开关
etcd.Register(etcd.ETCDKEY_GAME_CONFIG_GLOBAL, webapi.GameConfigGlobal{}, platformConfigEvent)
// 游戏场次配置
etcd.Register(etcd.ETCDKEY_GAMECONFIG_PREFIX, webapi.GameFree{}, platformConfigEvent)
// 平台包数据
etcd.Register(etcd.ETCDKEY_PACKAGE_PREFIX, webapi.AppInfo{}, platformConfigEvent)
// 客户端游戏入口开关
etcd.Register(etcd.ETCDKEY_PACKAGE_ENTRYSWITCH, webapi.EntrySwitch{}, platformConfigEvent)
// 公告
etcd.Register(etcd.ETCDKEY_GAME_NOTICE, webapi.CommonNoticeList{}, platformConfigEvent)
// 比赛配置
etcd.Register(etcd.ETCDKEY_GAME_MATCH, webapi.GameMatchDateList{}, platformConfigEvent)
// 比赛场类型
etcd.Register(etcd.ETCDKEY_GAME_MATCH_TYPE, webapi.GameMatchType{}, platformConfigEvent)
// 个人水池配置
etcd.Register(etcd.ETCDKEY_PLAYERPOOL, webapi.PlayerPool{}, platformConfigEvent)
// 商品兑换
etcd.Register(etcd.ETCDKEY_SHOP_EXCHANGE, webapi.ExchangeShopList{}, platformConfigEvent)
// 商城商品
etcd.Register(etcd.ETCDKEY_SHOP_ITEM, webapi.ItemShopList{}, platformConfigEvent)
// 集卡活动
etcd.Register(etcd.ETCDKEY_ACT_Collect, webapi.WelfareCollectConfig{}, platformConfigEvent)
// 渠道开关
etcd.Register(etcd.ETCDKEY_ChannelSwitch, webapi.ChannelSwitchConfig{}, platformConfigEvent)
// 组配置
etcd.Register(etcd.ETCDKEY_GROUPCONFIG_PREFIX, webapi.GameConfigGroup{}, platformConfigEvent)
// 黑名单配置
etcd.Register(etcd.ETCDKEY_BLACKLIST_PREFIX, BlackInfoApi{}, handlerEvent)
// 代理
etcd.Register(etcd.ETCDKEY_PROMOTER_PREFIX, PromoterConfig{}, handlerEvent)
// 7日签到
etcd.Register(etcd.ETCDKEY_ACT_7SIGN, webapi.Welfare7SignDateList{}, platformConfigEvent)
// 转盘
etcd.Register(etcd.ETCDKEY_ACT_TURNPLATE, webapi.WelfareTurnplateDateList{}, platformConfigEvent)
// 盲盒
etcd.Register(etcd.ETCDKEY_ACT_BLINDBOX, webapi.WelfareBlindBoxDataList{}, platformConfigEvent)
// 首充
etcd.Register(etcd.ETCDKEY_ACT_FIRSTPAY, webapi.WelfareFirstPayDataList{}, platformConfigEvent)
// 连充
etcd.Register(etcd.ETCDKEY_ACT_CONTINUOUSPAY, webapi.WelfareContinuousPayDataList{}, platformConfigEvent)
// VIP
etcd.Register(etcd.ETCDKEY_VIP_CFG, webapi.VIPcfgDataList{}, platformConfigEvent)
// 象棋段位
etcd.Register(etcd.ETCDKEY_CHESSRANK_CFG, webapi.ChessRankcfgData{}, platformConfigEvent)
// 手机积分
etcd.Register(etcd.ETCDKEY_ACT_PHONELOTTERY, webapi.WelfarePhoneLotteryStatus{}, platformConfigEvent)
// 邀请活动
etcd.Register(etcd.ETCDKEY_ACT_Invite, webapi.ActInviteConfig{}, platformConfigEvent)
// 赛季通行证
etcd.Register(etcd.ETCDKEY_ACT_Permit, webapi.ActPermitConfig{}, platformConfigEvent)
// 钻石抽奖
etcd.Register(etcd.ETCDKEY_DIAMOND_LOTTERY, webapi.DiamondLotteryConfig{}, platformConfigEvent)
// 道具列表
etcd.Register(etcd.ETCDKEY_Item, webapi.ItemConfig{}, platformConfigEvent)
// 皮肤配置
etcd.Register(etcd.ETCDKEY_SKin, webapi.SkinConfig{}, platformConfigEvent)
//排行榜奖励配置
etcd.Register(etcd.ETCDKEY_RANK_TYPE, webapi.RankTypeConfig{}, platformConfigEvent)
//获奖记录配置
etcd.Register(etcd.ETCDKEY_AWARD_CONFIG, webapi.AwardLogConfig{}, platformConfigEvent)
// 新手引导
etcd.Register(etcd.ETCDKEY_GUIDE, webapi.GuideConfig{}, platformConfigEvent)
// 比赛观众
etcd.Register(etcd.ETCDKEY_MatchAudience, webapi.MatchAudience{}, handlerEvent)
// 小精灵配置
etcd.Register(etcd.ETCDKEY_Spirit, webapi.SpiritConfig{}, platformConfigEvent)
// 竞技馆房间配置
etcd.Register(etcd.ETCDKEY_RoomConfig, webapi.RoomConfig{}, handlerEvent)
// 竞技馆系统房间配置
etcd.Register(etcd.ETCDKEY_RoomConfigSystem, webapi.RoomConfigSystem{}, handlerEvent)
// 竞技馆房间类型配置
etcd.Register(etcd.ETCDKEY_RoomType, webapi.RoomType{}, handlerEvent)
//娃娃机配置
etcd.Register(etcd.ETCDKEY_MACHINE, webapi.MachineConfig{}, platformConfigEvent)
}
func platformConfigEvent(ctx context.Context, completeKey string, isInit bool, event *clientv3.Event, data interface{}) {
if event.Type == clientv3.EventTypeDelete {
return
}
if data == nil {
return
}
switch config := data.(type) {
case *webapi.WelfareCollectConfig:
WelfareMgrSington.UpdateCollectConfig(config)
case *webapi.ItemShopList:
ShopMgrSington.UpdateItemShop(config)
case *webapi.ExchangeShopList:
ShopMgrSington.UpExShop(config)
case *webapi.PlayerPool:
PlatformMgrSingleton.GetConfig(config.Platform).PlayerPool = config
case *webapi.EntrySwitch:
PlatformMgrSingleton.GetConfig(config.Platform).EntrySwitch[config.Index] = config
PlatformMgrSingleton.ChangeEntrySwitch(config.Platform, config)
case *webapi.CommonNoticeList:
PlatformMgrSingleton.GetConfig(config.Platform).CommonNotices = config
if !isInit {
// 通知公共变更
PlayerMgrSington.BroadcastMessageToPlatform(config.Platform, int(hallproto.GameHallPacketID_PACKET_SC_NoticeChange), &hallproto.SCNoticeChange{})
}
case *webapi.GameConfigGlobal:
if isInit {
for _, v := range config.GetGameStatus() {
gameId := v.GetGameId()
status := v.GetStatus()
PlatformMgrSingleton.GetGlobalConfig().GameStatus[gameId] = status
}
} else {
cfgs := make([]*hallproto.GameConfig1, 0)
for _, v := range config.GetGameStatus() {
gameId := v.GetGameId() // gamefreeid
status := v.GetStatus()
if PlatformMgrSingleton.GetGlobalConfig().GameStatus[gameId] != status {
cfgs = append(cfgs, &hallproto.GameConfig1{
LogicId: gameId,
Status: status,
})
}
PlatformMgrSingleton.GetGlobalConfig().GameStatus[gameId] = status
}
PlatformMgrSingleton.ChangeGameStatus(cfgs)
}
case *webapi.Platform:
if isInit {
PlatformMgrSingleton.CreateDefaultPlatform()
}
PlatformMgrSingleton.UpsertPlatform(config.PlatformName, config.Isolated, config.Disabled, config.Id,
config.CustomService, config.BindOption, config.ServiceFlag, config.UpgradeAccountGiveCoin,
config.NewAccountGiveCoin, config.PerBankNoLimitAccount, config.ExchangeMin, config.ExchangeLimit,
config.ExchangeTax, config.ExchangeFlow, config.ExchangeFlag, config.SpreadConfig, config.VipRange, "",
nil, config.VerifyCodeType, nil /*config.ThirdGameMerchant,*/, config.CustomType,
false, config.NeedSameName, config.ExchangeForceTax, config.ExchangeGiveFlow, config.ExchangeVer,
config.ExchangeBankMax, config.ExchangeAlipayMax, 0, config.PerBankNoLimitName, config.IsCanUserBindPromoter,
config.UserBindPromoterPrize, false, config.ExchangeMultiple, false, config.MerchantKey,
config.BindTelReward)
case *webapi.GameFree:
var err error
s := strings.TrimPrefix(completeKey, etcd.ETCDKEY_GAMECONFIG_PREFIX)
arr := strings.Split(s, "/")
if len(arr) > 1 {
pltId := arr[0]
if err == nil {
PlatformMgrSingleton.UpsertGameFree(pltId, config)
}
}
case *webapi.AppInfo:
if config.PlatformId == 0 {
config.PlatformId = int32(DefaultPlatformInt)
}
PlatformMgrSingleton.GetGlobalConfig().PackageList[config.PackageName] = config
PlatformMgrSingleton.GetGlobalConfig().PackageList[config.BundleId] = config
case *webapi.GameMatchDateList:
if isInit {
TournamentMgr.UpdateData(true, config)
} else {
TournamentMgr.UpdateData(false, config)
}
case *webapi.GameMatchType:
if isInit {
TournamentMgr.UpdateTypeList(true, config)
} else {
TournamentMgr.UpdateTypeList(false, config)
}
case *webapi.ChannelSwitchConfig:
PlatformMgrSingleton.GetConfig(config.Platform).ChannelSwitch[config.GetTp()] = config
if !isInit {
// 通知变更
PlayerMgrSington.BroadcastMessageToPlatform(config.Platform, int(playerproto.PlayerPacketID_PACKET_SCExchangeChannel), &playerproto.SCExchangeChannel{
Datas: []*playerproto.ChannelSwitch{{
Tp: config.Tp,
OnChannelName: config.OnChannelName,
}},
})
}
case *webapi.GameConfigGroup:
PlatformGameGroupMgrSington.UpsertGameGroup(config)
case *webapi.Welfare7SignDateList:
WelfareMgrSington.UpdateSign7(config)
case *webapi.WelfareTurnplateDateList:
WelfareMgrSington.UpdateTurnplate(config)
case *webapi.WelfareBlindBoxDataList:
WelfareMgrSington.UpdateBlindBox(config)
case *webapi.WelfareFirstPayDataList:
WelfareMgrSington.UpdateFirstPay(config)
case *webapi.WelfareContinuousPayDataList:
WelfareMgrSington.UpdateContinuousPay(config)
case *webapi.VIPcfgDataList:
VipMgrSington.UpdateVIPcfg(config)
case *webapi.ChessRankcfgData:
ChessRankMgrSington.UpdateChessRankConfig(config)
case *webapi.WelfarePhoneLotteryStatus:
WelfareMgrSington.UpdatePhoneLotteryStatus(config)
case *webapi.DiamondLotteryConfig:
WelfareMgrSington.UpdateDiamondLotteryConfig(config)
case *webapi.ActInviteConfig:
PlatformMgrSingleton.GetConfig(config.Platform).ActInviteConfig = config
case *webapi.ActPermitConfig:
PlatformMgrSingleton.GetConfig(config.Platform).ActPermitConfig = config
st := new(model.PermitStartTs)
permit := model.GetStrKVGameData(common.PermitStartTsKey + config.Platform)
if permit != "" {
if err := json.Unmarshal([]byte(permit), st); err != nil {
logger.Logger.Errorf("permit startts error: %v", err)
return
}
// 修改循环周期
endTs := st.StartTs + int64(config.GetDays()*24*3600)
if st.StartTs > 0 && endTs != st.EndTs {
st.EndTs = endTs
}
PlatformMgrSingleton.GetConfig(config.Platform).PermitStartTs = st.StartTs
PlatformMgrSingleton.GetConfig(config.Platform).PermitEndTs = st.EndTs
} else {
startTs := common.GetDayStartTs(config.StartTs)
endTs := startTs + int64(config.Days*24*3600)
st.StartTs = startTs
st.EndTs = endTs
PlatformMgrSingleton.GetConfig(config.Platform).PermitStartTs = startTs
PlatformMgrSingleton.GetConfig(config.Platform).PermitEndTs = endTs
}
f1 := func() {
if st.StartTs <= 0 || st.EndTs <= 0 {
return
}
b, err := json.Marshal(st)
if err != nil {
logger.Logger.Errorf("permit startts save error: %v", err)
} else {
logger.Logger.Infof("update permit startts: %v %v", st.StartTs, st.EndTs)
err := model.UptStrKVGameData(common.PermitStartTsKey+config.Platform, string(b))
if err != nil {
logger.Logger.Errorf("permit startts update error:%v", err)
}
}
}
f2 := func() {
if st.StartTs > 0 {
mq.Write(&model.BackendPermitCycle{
Platform: config.Platform,
StartTs: st.StartTs,
EndTs: st.EndTs - 1,
})
}
}
if isInit {
f1()
f2()
} else {
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
f1()
return nil
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
f2()
})).StartByExecutor("permit_start_ts")
}
case *webapi.ItemConfig:
PlatformMgrSingleton.GetConfig(config.Platform).ItemConfig = config
srvdata.GameItemMgr.SetConfig(config)
if !isInit {
var items []*serverproto.DB_GameItem
for _, v := range config.GetItems() {
items = append(items, &serverproto.DB_GameItem{
Id: v.GetId(),
Name: v.GetName(),
ShowLocation: v.GetShowLocation(),
Classify: v.GetClassify(),
Type: v.GetType(),
Effect0: v.GetEffect0(),
Effect: v.GetEffect(),
SaleType: v.GetSaleType(),
SaleGold: v.GetSaleGold(),
Composition: v.GetComposition(),
CompositionMax: v.GetCompositionMax(),
Time: v.GetTime(),
Location: v.GetLocation(),
Describe: v.GetDescribe(),
Num: v.GetNum(),
Value: v.GetValue(),
Entity: v.GetEntity(),
Icon: v.GetIcon(),
})
}
if len(items) > 0 {
PlayerMgrSington.BroadcastMessageToPlatform(config.Platform, int(playerproto.PlayerPacketID_PACKET_SCItem), &playerproto.SCItem{
Items: items,
})
}
}
case *webapi.SkinConfig:
PlatformMgrSingleton.GetConfig(config.Platform).SkinConfig = config
case *webapi.RankTypeConfig:
PlatformMgrSingleton.GetConfig(config.Platform).RankTypeConfig = config
case *webapi.AwardLogConfig:
PlatformMgrSingleton.GetConfig(config.Platform).AwardLogConfig = config
case *webapi.GuideConfig:
PlatformMgrSingleton.GetConfig(config.Platform).GuideConfig = config
case *webapi.MachineConfig:
PlatformMgrSingleton.GetConfig(config.Platform).MachineConfig = config
case *webapi.SpiritConfig:
PlatformMgrSingleton.GetConfig(config.Platform).SpiritConfig = config
if !isInit {
PlayerMgrSington.BroadcastDataConfigToPlatform(config.Platform, common.DataConfigSprite)
}
default:
logger.Logger.Errorf("etcd completeKey:%s, Not processed", completeKey)
}
}
func handlerEvent(ctx context.Context, completeKey string, isInit bool, event *clientv3.Event, data interface{}) {
var plt string
var param []int
equalFunc := func(key string) bool {
plt = ""
param = param[:0]
if strings.HasPrefix(completeKey, key) {
arr := strings.Split(strings.TrimPrefix(completeKey, key), "/")
for k, v := range arr {
if v == "" {
continue
}
if len(v) > 0 {
plt = v
for _, v := range arr[k+1:] {
n, err := strconv.Atoi(v)
if err != nil {
continue
}
param = append(param, n)
}
return true
}
}
}
return false
}
switch {
case equalFunc(etcd.ETCDKEY_BLACKLIST_PREFIX):
var config *BlackInfoApi
if data != nil {
config = data.(*BlackInfoApi)
}
if isInit {
if config == nil {
return
}
BlackListMgrSington.InitBlackInfo(config)
} else {
switch event.Type {
case clientv3.EventTypeDelete:
dirs := strings.Split(string(event.Kv.Key), "/")
n := len(dirs)
if n > 0 {
last := dirs[n-1]
id, err := strconv.Atoi(last)
if err == nil {
if value, exist := BlackListMgrSington.BlackList[int32(id)]; exist {
BlackListMgrSington.RemoveBlackInfo(value.Id, value.Platform)
}
}
}
case clientv3.EventTypePut:
if config == nil {
return
}
BlackListMgrSington.UpsertBlackInfo(config)
if (config.Space & int32(BlackState_Login)) != 0 {
var targetPlayer []*Player //确定用户是否在线
for _, value := range PlayerMgrSington.players {
_, ok := BlackListMgrSington.CheckPlayerInBlack(value.PlayerData, BlackState_Login)
if ok {
targetPlayer = append(targetPlayer, value)
}
}
for _, p := range targetPlayer {
if p.sid != 0 {
p.Kickout(int32(loginproto.SSDisconnectTypeCode_SSDTC_BlackList))
} else {
LoginStateMgrSington.LogoutByAccount(p.AccountId)
}
}
}
}
}
case equalFunc(etcd.ETCDKEY_PROMOTER_PREFIX):
var config *PromoterConfig
if data != nil {
config = data.(*PromoterConfig)
}
if isInit {
if config == nil {
return
}
PromoterMgrSington.AddConfig(config)
} else {
switch event.Type {
case clientv3.EventTypeDelete:
dirs := strings.Split(string(event.Kv.Key), "/")
n := len(dirs)
if n > 0 {
promoterConfig := dirs[n-1]
PromoterMgrSington.RemoveConfigByKey(promoterConfig)
}
case clientv3.EventTypePut:
if config == nil {
return
}
PromoterMgrSington.AddConfig(config)
}
}
case equalFunc(etcd.ETCDKEY_MatchAudience):
switch event.Type {
case clientv3.EventTypePut:
if data == nil {
return
}
config := data.(*webapi.MatchAudience)
PlatformMgrSingleton.AddMatchAudience(config)
if !isInit {
p := PlayerMgrSington.GetPlayerBySnId(config.GetSnId())
if p != nil {
p.SCDataConfig(common.DataConfigMatchAudience)
}
}
case clientv3.EventTypeDelete:
if plt == "" || len(param) == 0 {
return
}
PlatformMgrSingleton.DelMatchAudience(plt, int32(param[0]))
if !isInit {
p := PlayerMgrSington.GetPlayerBySnId(int32(param[0]))
if p != nil {
p.SCDataConfig(common.DataConfigMatchAudience)
}
}
}
case equalFunc(etcd.ETCDKEY_RoomType):
switch event.Type {
case clientv3.EventTypePut:
if data == nil {
return
}
config := data.(*webapi.RoomType)
PlatformMgrSingleton.UpdateRoomType(config)
if !isInit {
//PlayerMgrSington.BroadcastMessageToPlatform(config.GetPlatform(), int(0), nil)
}
case clientv3.EventTypeDelete:
if plt == "" || len(param) == 0 {
return
}
PlatformMgrSingleton.DelRoomType(plt, int32(param[0]))
if !isInit {
//PlayerMgrSington.BroadcastMessageToPlatform(plt, int(0), nil)
}
}
case equalFunc(etcd.ETCDKEY_RoomConfig):
switch event.Type {
case clientv3.EventTypePut:
if data == nil {
return
}
config := data.(*webapi.RoomConfig)
PlatformMgrSingleton.UpdateRoomConfig(config)
if !isInit {
//PlayerMgrSington.BroadcastMessageToPlatform(config.GetPlatform(), int(0), nil)
}
case clientv3.EventTypeDelete:
if plt == "" || len(param) == 0 {
return
}
PlatformMgrSingleton.DelRoomConfig(plt, int32(param[0]))
if !isInit {
//PlayerMgrSington.BroadcastMessageToPlatform(plt, int(0), nil)
}
}
case equalFunc(etcd.ETCDKEY_RoomConfigSystem):
switch event.Type {
case clientv3.EventTypePut:
if data == nil {
return
}
config := data.(*webapi.RoomConfigSystem)
PlatformMgrSingleton.GetConfig(config.GetPlatform()).RoomConfigSystem[config.GetId()] = config
switch config.GetOn() {
case common.On:
CustomRoomMgrSingle.TouchCreate(config.GetPlatform(), config.GetId())
case common.Off:
if !isInit {
CustomRoomMgrSingle.TryDestroy(config.GetPlatform(), config.GetId())
}
}
case clientv3.EventTypeDelete:
if plt == "" || len(param) == 0 {
return
}
if !isInit {
CustomRoomMgrSingle.TryDestroy(plt, int32(param[0]))
}
delete(PlatformMgrSingleton.GetConfig(plt).RoomConfigSystem, int32(param[0]))
}
default:
logger.Logger.Errorf("etcd completeKey:%s, Not processed", completeKey)
}
}