game_sync/worldsrv/etcd.go

405 lines
14 KiB
Go

package main
import (
"context"
"encoding/json"
"strconv"
"strings"
"time"
"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"
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)
// 赠送
etcd.Register(etcd.ETCDKEY_ACT_GIVE_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)
}
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 {
// 通知公共变更
for _, v := range PlayerMgrSington.playerOfPlatform[config.Platform] {
if v != nil && v.IsOnLine() {
v.SendToClient(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 {
// 通知变更
for _, v := range PlayerMgrSington.playerOfPlatform[config.Platform] {
if v != nil && v.IsOnLine() {
v.SendToClient(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
}
f := func() {
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
if st.StartTs <= 0 || st.EndTs <= 0 {
return nil
}
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)
}
}
return nil
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
if st.StartTs > 0 {
LogChannelSingleton.WriteLog(&model.BackendPermitCycle{
Platform: config.Platform,
StartTs: st.StartTs,
EndTs: st.EndTs - 1,
})
}
})).StartByExecutor("permit_start_ts")
}
if isInit {
time.AfterFunc(time.Second*5, f) //todo 优化
} else {
f()
}
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 {
for _, v := range PlayerMgrSington.playerOfPlatform[config.Platform] {
if v != nil && v.IsOnLine() {
v.SendToClient(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
default:
logger.Logger.Errorf("etcd completeKey:%s, Not processed", completeKey)
}
PlatformMgrSingleton.GetConfig("1").GuideConfig = &webapi.GuideConfig{
Platform: "1",
On: common.On,
Skip: common.On,
}
}
func handlerEvent(ctx context.Context, completeKey string, isInit bool, event *clientv3.Event, data interface{}) {
if data == nil {
return
}
switch config := data.(type) {
case *BlackInfoApi:
if isInit {
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:
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 *PromoterConfig:
if isInit {
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:
PromoterMgrSington.AddConfig(config)
}
}
case *ActGivePlateformConfig:
if isInit || event.Type == clientv3.EventTypePut {
ActMgrSington.AddGiveConfig(config, config.Platform)
}
default:
logger.Logger.Errorf("etcd completeKey:%s, Not processed", completeKey)
}
}