package service import ( "fmt" "sort" "strconv" "strings" "crazy-fox-backend-api/config" "crazy-fox-backend-api/global" "crazy-fox-backend-api/model" "crazy-fox-backend-api/plugin/nsq" "crazy-fox-backend-api/repo" "crazy-fox-backend-api/repo/okeys" "crazy-fox-backend-api/utils" "crazy-fox-backend-api/utils/fileop" "github.com/dablelv/go-huge-util/conv" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" "golang.org/x/sync/errgroup" ) // configService 配置模块服务 type configService struct{} // GetGeneralConf 获取公共配置 func (This *configService) GetGeneralConf() model.ResGeneralConf { actListMap := Props.MakeActSkinMap() var eg errgroup.Group var generalConf model.ResGeneralConf // 遍历活动型道具类型列表 generalConf.NormalProps = Props.BuildPropsConf(&config.NormalPropsList, actListMap) // 遍历功能型道具类型列表 generalConf.SimpleProps = Props.BuildPropsConf(&config.SimplePropsList, actListMap) // 获取用户数数分组 eg.Go(func() error { generalConf.SsGroup = Config.BuildSsGroup() return nil }) // 获取老虎机权重分组 eg.Go(func() error { generalConf.SlotWeightGroup = Config.BuildSlotWeightGroup() return nil }) // 获取老虎机权重分组 eg.Go(func() error { generalConf.VersionList = Config.getVersions() return nil }) _ = eg.Wait() return generalConf } // SaveJson 保存Json文件 func (This *configService) SaveJson(data any, key string) error { filename := fmt.Sprintf("%s%d.json", key, utils.CurTimestamp()) // 保存文件名到数据库 oneStaticConf, err := repo.Config.GetOneStaticConf(key) oneStaticConf.Path = filename if err != nil { // insert oneStaticConf.Config = key if _, err = repo.Insert(&oneStaticConf); err != nil { return errors.WithStack(err) } } else { // update if err = repo.Update(&oneStaticConf, "config"); err != nil { return errors.WithStack(err) } } repo.HSetCache(okeys.StaticConfig(), key, filename) // 保存文件数据到文件 json, err := jsoniter.Marshal(data) if err != nil { return errors.WithStack(err) } dirPath := utils.BuildAP("config") return fileop.FileSave(json, dirPath, filename) } // GetBasicConf 获取基础配置 func (This *configService) GetBasicConf(it model.ItemTitle) (string, error) { if it.Item == "" || it.Title == "" { return "", errors.New("参数不能为空字符串") } basicConf, _ := repo.Config.GetBasicConf(it) return basicConf.Content, nil } // UpdateBasicConf 更新基础配置 func (This *configService) UpdateBasicConf(updateConf model.TBasicConfig) error { // update if updateConf.Id != 0 { if err := repo.Config.UpdateBasicConf(updateConf); err != nil { return errors.WithStack(err) } } else { basicConf, err := repo.Config.GetBasicConf(updateConf.ItemTitle) if err != nil { // 配置不存在 Insert if _, err = repo.Insert(&updateConf); err != nil { return errors.WithStack(err) } } else { // update updateConf.Id = basicConf.Id if err = repo.Config.UpdateBasicConf(updateConf); err != nil { return errors.WithStack(err) } } } // 缓存 repo.HSetCache(okeys.BasicConfigKey(), updateConf.ItemTitle.String(), updateConf.Content) if err := This.updateConJson(); err != nil { return err } return nil } // GetSystemConf 获取系统配置 func (This *configService) GetSystemConf(it model.ItemTitle) (string, error) { if it.Item == "" || it.Title == "" { return "", errors.New("参数不能为空字符串") } basicConf, _ := repo.Config.GetSystemConf(it) return basicConf.Content, nil } // UpdateSystemConf 更新系统配置 func (This *configService) UpdateSystemConf(updateConf model.TSystemConfig) error { // update if updateConf.Id != 0 { if err := repo.Config.UpdateSystemConf(updateConf); err != nil { return errors.WithStack(err) } } else { systemConf, err := repo.Config.GetSystemConf(updateConf.ItemTitle) if err != nil { // 配置不存在 Insert if _, err = repo.Insert(&updateConf); err != nil { return errors.WithStack(err) } } else { // update updateConf.Id = systemConf.Id if err = repo.Config.UpdateSystemConf(updateConf); err != nil { return errors.WithStack(err) } } } // 缓存 repo.HSetCache(okeys.SystemConfig(), updateConf.ItemTitle.String(), updateConf.Content) return nil } func (This *configService) updateConJson() error { basicConfList := repo.Search[model.TBasicConfig]("") mapItem := []string{"android", "ios", "getSpinAd", "onoff"} jsonMap := make(map[string]map[string]any, len(mapItem)) epItem := []string{"Url", "BeginnerReward", "Game"} epTitle := []string{"fbInviteSpin", "initialSpins", "repairMoney"} json := make(map[string]any, len(basicConfList)-len(mapItem)) for _, basicConfig := range basicConfList { if utils.InSlice(basicConfig.Item, mapItem) { if _, OK := jsonMap[basicConfig.Item]; OK { jsonMap[basicConfig.Item][basicConfig.Title] = basicConfig.Content } else { jsonMap[basicConfig.Item] = map[string]any{basicConfig.Title: basicConfig.Content} } } else if basicConfig.Title == "repairMoney" { json["initialCoins"] = basicConfig.Content } else if utils.InSlice(basicConfig.Item, epItem) || utils.InSlice(basicConfig.Title, epTitle) { json[basicConfig.Title] = basicConfig.Content } } for s, m := range jsonMap { json[s] = m } return This.SaveJson(json, "Game") } // GetCommonConf 获取公共配置 func (This *configService) GetCommonConf(typ string) (commonConf model.CommonConf, err error) { if typ == "" { return commonConf, errors.New("参数不能为空字符串") } commonConf, err = repo.Config.GetCommonConf(typ) return } // UpdateCommonConf 更新公共配置 func (This *configService) UpdateCommonConf(commonConf model.CommonConf) (err error) { // update if commonConf.Id != 0 { if err = repo.Update(&commonConf, "id"); err != nil { return errors.WithStack(err) } } else { var basicConf model.CommonConf basicConf, err = This.GetCommonConf(commonConf.Type) if err != nil { // 配置不存在 Insert if _, err = repo.Insert(&commonConf); err != nil { return errors.WithStack(err) } } else { // update commonConf.Id = basicConf.Id if err = repo.Update(&commonConf, "id"); err != nil { return errors.WithStack(err) } } } return } // GetChestRewardBySkin 获取皮肤宝箱奖励配置 func (This *configService) GetChestRewardBySkin(skin int64) []model.ChestSkinReward { // 有缓存 if cache := repo.Config.HGetChestReward(skin); cache != "" { var reward []model.ChestSkinReward if err := jsoniter.UnmarshalFromString(cache, &reward); err != nil { panic(errors.Wrap(err, "皮肤宝箱奖励Json解析失败")) } } return repo.Config.GetChestReward(skin) } // GetTimeLimitSkinChests 获取限时皮肤宝箱选项 func (This *configService) GetTimeLimitSkinChests() model.Options { chests := repo.Search[model.TChestSkinConfig2]("") options := make([]model.Option, 0, len(chests)) for _, chest := range chests { if chest.StarPro.CardType == 1 { options = append(options, model.Option{ Value: chest.Id, Label: chest.Name, }) } } return options } func (This *configService) getVersions() []string { versions := repo.SearchOne[model.TVersionSet]("").Content split := strings.Split(versions, ",") if len(split) != 0 { return split } return []string{"1.7.5.0", "1.7.6.0", "1.7.7.0", "1.7.8.0", "1.7.9.0", "1.8.0.0", "1.8.1.0", "1.8.2.0", "1.8.3.0", "1.8.4.0", "1.8.5", "1.8.6", "1.9"} } func (This *configService) BasicConf() []model.TBasicConfig { return repo.Search[model.TBasicConfig]("") } func (This *configService) BasicConfEdit(req model.TBasicConfig) error { if err := This.UpdateBasicConf(req); err != nil { return errors.WithStack(err) } return nil } func (This *configService) BasicBet() []model.TCrazyBetConfig { return repo.Search[model.TCrazyBetConfig]("Where actData = 0") } func (This *configService) BasicBetEdit(req []model.TCrazyBetConfig, typ int64) error { if _, err := repo.ReplaceStruct[model.TCrazyBetConfig](req, repo.WithKeys("id"), repo.WithWhere("Where actData = ?", typ)); err != nil { return errors.WithStack(err) } data := This.buildBasicBetJson() if err := This.SaveJson(data, "CrazyBetConfig"); err != nil { return errors.WithStack(err) } return nil } func (This *configService) SuperBet() (conf model.SuperCrazyBetConf) { conf.BetList = repo.Search[model.TCrazyBetConfig]("Where actData = 1") actSpinsLimit, _ := This.GetSystemConf(model.ItemTitle{Item: "activtity14", Title: "actSpinsLimit"}) conf.Limit = conv.ToAny[int64](actSpinsLimit) return conf } func (This *configService) SuperBetEdit(req model.SuperCrazyBetConf) error { sysConf := model.TSystemConfig{ ItemTitle: model.ItemTitle{Item: "activtity14", Title: "actSpinsLimit"}, Content: strconv.FormatInt(req.Limit, 10), Memo: "超级Bet触发体力配置", } if err := This.UpdateSystemConf(sysConf); err != nil { return err } if err := This.BasicBetEdit(req.BetList, 1); err != nil { return errors.WithStack(err) } return nil } func (This *configService) buildBasicBetJson() (json model.CrazyBetStatic) { list := repo.Search[model.TCrazyBetConfig]("") for _, betConfig := range list { switch betConfig.ActData { case 0: json.NormalConfig = append(json.NormalConfig, betConfig.CrazyBetBaseConf) case 1: json.SuperBetConfig = append(json.SuperBetConfig, betConfig.CrazyBetBaseConf) } } actSpinsLimit, _ := This.GetSystemConf(model.ItemTitle{Item: "activtity14", Title: "actSpinsLimit"}) json.ActSpinsLimit = conv.ToAny[int64](actSpinsLimit) return json } func (This *configService) UpLimitConf() map[string][]model.UpLimitConf { confList := repo.Search[model.TUpLimitConfig]("") confMap := make(map[string][]model.UpLimitConf, len(confList)) for _, limit := range confList { confMap[limit.Type] = limit.Data } return confMap } func (This *configService) UpLimitConfEdit(req map[string][]model.UpLimitConf) error { updateConf := make([]map[string]any, 0, len(req)) for s, confs := range req { updateConf = append(updateConf, map[string]any{"type": s, "data": confs}) } if err := repo.UpdateByMap[model.TUpLimitConfig](updateConf, "type"); err != nil { return errors.WithStack(err) } return nil } func (This *configService) UserGroups() []model.UserSsGroup { confList := repo.Search[model.TUserGroup2]("Where cid = 5") ssGroupsHide := repo.Config.HGetAllSSGroupHide() ssGroupsUpdate := repo.Config.HGetAllSSGroupUpdate() groups := make([]model.UserSsGroup, 0, len(confList)) for _, conf := range confList { if conf.GroupId != 0 { conf.GroupId = conf.Id } groups = append(groups, model.UserSsGroup{ UserGroupBaseConf: conf.UserGroupBaseConf, ShowStatus: utils.Ternary(utils.InSlice(conf.Id, ssGroupsHide), int64(0), 1), UpdateStatus: utils.Ternary(utils.InSlice(conf.Id, ssGroupsUpdate), int64(1), 0), }) } sort.SliceStable(groups, func(i, j int) bool { return groups[i].Sort > groups[j].Sort }) return groups } func (This *configService) UserGroupsShow(req *model.UserGroupStatus) error { // 全量更新 if req.Id == -1 { ssGroups := repo.Search[model.TSsGroup]("where cid = ?", 5) cacheMap := make(map[string]any, len(ssGroups)) for _, one := range ssGroups { if one.Name == "数数-默认分组" { one.Id = 0 } id := strconv.FormatInt(one.Id, 10) cacheMap[id] = id } repo.ClearAndHMSetCache(okeys.SsGroupHide(), cacheMap) } else { id := strconv.FormatInt(req.Id, 10) if !utils.IsEmpty(req.Status) { repo.Config.HDelSSGroupHide(id) } else { repo.Config.HMSetSSGroupHide(map[string]any{id: id}) } } return nil } func (This *configService) UserGroupsUpdate(req *model.UserGroupStatus) error { id := strconv.FormatInt(req.Id, 10) if req.Status < 1 { repo.Config.HDelSSGroupUpdate(id) } else { repo.Config.HMSetSSGroupUpdate(map[string]any{id: id}) } return nil } func (This *configService) GetOtherConf() (model.CommonOtherConf, error) { var otherConf model.CommonOtherConf otherConf.GuideLastStep = This.getGuideLastStepConf() return otherConf, nil } func (This *configService) getGuideLastStepConf() (guideConf model.GuideLastStep) { conf, err := This.GetCommonConf(okeys.GuideLastStep()) if err != nil { return } err = jsoniter.UnmarshalFromString(conf.Conf, &guideConf) if err != nil { return } return guideConf } func (This *configService) GuideLastStepEdit(req model.GuideLastStep) error { confStr, err := jsoniter.MarshalToString(req) if err != nil { return errors.WithStack(err) } // 更新数据库 if err = This.UpdateCommonConf(model.CommonConf{Type: okeys.GuideLastStep(), Name: "新手引导最后一步配置", Conf: confStr}); err != nil { return errors.WithStack(err) } // 更新缓存 repo.SetCache(okeys.GuideLastStep(), confStr) return nil } func (This *configService) GetSkinOptions(skinName string) []model.Option2 { skinList := Activity.GetOneActImgNameByType(skinName).Content if utils.IsEmpty(skinList) { return []model.Option2{} } options := make([]model.Option2, 0, len(skinList)) for _, content := range skinList { options = append(options, model.Option2{Value: content.Type, Label: content.Name}) } return options } // BuildSsGroup 构建数数分组 func (This *configService) BuildSsGroup() model.Options { cacheKey := config.SsGroup // 缓存存在 且未过期 if cache, exist := global.LocalCache.Get(cacheKey); exist { return cache.(model.Options) } ssGroups := repo.Search[model.TSsGroup]("where cid = ?", 5) hideIdArr := repo.Config.GetHideSsGroup() ssGroupOptions := make(model.Options, 0, len(ssGroups)) for i := 0; i < len(ssGroups); i++ { one := ssGroups[i] if utils.InSlice(one.Id, hideIdArr) { continue } if one.Name == "数数-默认分组" { one.Id = 0 } ssGroupOptions = append(ssGroupOptions, model.Option{ Label: one.Name, Value: one.Id, }) } if len(ssGroupOptions) == 0 { ssGroupOptions = append(ssGroupOptions, model.Option{ Label: "数数-默认分组", Value: 0, }) } // 缓存道具皮肤配置 global.LocalCache.SetDefault(cacheKey, ssGroupOptions) return ssGroupOptions } // BuildSlotWeightGroup 构建老虎机权重分组 func (This *configService) BuildSlotWeightGroup() model.Options { cacheKey := config.SlotWeightGroupCacheKey // 缓存存在 且未过期 if cache, exist := global.LocalCache.Get(cacheKey); exist { return cache.(model.Options) } slotWeightGroupsList := repo.Search[model.TSlotWeightGroup]("") slotWeightGroups := make(model.Options, 0, len(slotWeightGroupsList)) for i := 0; i < len(slotWeightGroupsList); i++ { one := slotWeightGroupsList[i] slotWeightGroups = append(slotWeightGroups, model.Option{ Label: one.Name, Value: one.Id, }) } // 缓存配置 global.LocalCache.SetDefault(cacheKey, slotWeightGroups) return slotWeightGroups } func (This *configService) SysNotice() []model.AnnouncementShow { confList := repo.Search[model.TAnnouncement](" Order By id desc") showList := make([]model.AnnouncementShow, 0, len(confList)) for _, one := range confList { oneShow := model.AnnouncementShow{ Id: one.Id, Title: one.Title, Content: one.Content, DateRange: []int64{one.Stime * 1000, one.Etime * 1000}, Device: one.Device, Usertype: one.Usertype, } _ = utils.Explode(&oneShow.Whitelist, one.Wlist, ",") _ = utils.Explode(&oneShow.Blacklist, one.Blist, ",") showList = append(showList, oneShow) } return showList } func (This *configService) SysNoticeEdit(req []model.AnnouncementShow) error { updateConf := make([]model.TAnnouncement, 0, len(req)) cacheMap := make(map[string]any, len(req)) for _, conf := range req { one := model.TAnnouncement{ AnnouncementCache: model.AnnouncementCache{ Id: conf.Id, Title: conf.Title, Content: conf.Content, Stime: conf.DateRange[0] / 1000, Etime: conf.DateRange[1] / 1000, Device: conf.Device, Usertype: conf.Usertype, Type: 0, Wlist: utils.Implode(conf.Whitelist, ","), Blist: utils.Implode(conf.Blacklist, ","), }, Isvalid: 0, AnnounceType: 0, } updateConf = append(updateConf, one) cacheMap[strconv.FormatInt(one.Id, 10)] = one.AnnouncementCache } delIds, err := repo.ReplaceStruct[model.TAnnouncement](updateConf, repo.WithKeys("id")) if err != nil { return errors.WithStack(err) } if !utils.IsEmpty(delIds) { delKeys := make([]string, 0, len(delIds)) for _, id := range delIds { delKeys = append(delKeys, okeys.AnnouncementNew(id)) } repo.DelCache(delKeys...) } repo.ClearAndHMSetCache(okeys.Announcement(), cacheMap) for id, one := range cacheMap { repo.ClearAndHMSetCacheByStruct(okeys.AnnouncementNew(id), one) } return nil } func (This *configService) StopServer() (showConf model.StopServerShowConf) { showConf.BasicConf = This.getStopServerConf() noticeList := repo.Search[model.TAnnouncement](" Order By id desc") showConf.NoticeOptions = make(model.Options, 0, len(noticeList)) for _, notice := range noticeList { showConf.NoticeOptions = append(showConf.NoticeOptions, model.Option{ Value: notice.Id, Label: notice.Title, }) } return showConf } func (This *configService) getStopServerConf() (showConf model.StopServerConf) { conf, err := This.GetCommonConf(okeys.StopServiceConfig()) if err != nil { return showConf } if err = jsoniter.UnmarshalFromString(conf.Conf, &showConf); err != nil { return showConf } return showConf } func (This *configService) StopServerEdit(req *model.StopServerConf) error { oldConf := This.getStopServerConf() // 配置改变 发送nsq if utils.IsEmpty(oldConf.Type) || oldConf.Type != req.Type { if err := nsq.SendNsqMsg(config.TopicActOnlineOff, req); err != nil { panic(errors.Wrap(err, "nsq 停服推送失败")) } } conf, err := jsoniter.MarshalToString(req) if err != nil { return errors.WithStack(err) } key := okeys.StopServiceConfig() if err = This.UpdateCommonConf(model.CommonConf{Type: key, Name: "停服配置", Conf: conf}); err != nil { return errors.WithStack(err) } repo.SetCache(key, conf) // 生成停服动态 staticJson := This.buildStopServerJson(req) if err = This.SaveJson(staticJson, "StopConfig"); err != nil { return errors.WithStack(err) } return nil } func (This *configService) buildStopServerJson(conf *model.StopServerConf) model.StopServerStatic { staticInfo := model.StopServerStatic{Type: conf.Type, Url: conf.Url} var content model.StopServerStaticContent if conf.Type > 1 { noticeInfo := repo.SearchOne[model.TAnnouncement]("Where id = ?", conf.AnnouncementId) content.Title = noticeInfo.Title content.Content = noticeInfo.Content content.Whitelist = []int64{} if conf.Type == 3 && !utils.IsEmpty(noticeInfo.Wlist) { _ = utils.Explode(&content.Whitelist, noticeInfo.Wlist, ",") } } staticInfo.Content = content return staticInfo } func (This *configService) Version() []string { versions := repo.SearchOne[model.TVersionSet]("").Content return strings.Split(versions, ",") } func (This *configService) VersionEdit(req []string) error { if err := repo.Update(&model.TVersionSet{Content: utils.Implode(req, ",")}, "content"); err != nil { return errors.WithStack(err) } return nil } func (This *configService) IosVersion() model.IosVersionConf { return repo.Config.MGetIosVersionConf() } func (This *configService) IosVersionEdit(req *model.IosVersionConf) error { mapCache := map[string]any{ okeys.OpenOline(): req.OpenOline, okeys.OpenOlineVersion(): req.OpenOlineVer, okeys.IsOpenMaple(): req.IsOpenMaple, } repo.MSetCache(mapCache) return nil } func (This *configService) LoginPopup() []model.TLoginBulletBox { return repo.Search[model.TLoginBulletBox]("") } func (This *configService) LoginPopupEdit(req []model.TLoginBulletBox) error { if _, err := repo.ReplaceStruct[model.TLoginBulletBox](req, repo.WithKeys("id")); err != nil { return errors.WithStack(err) } repo.DelCache(okeys.LoginBulletBox()) staticJson := This.buildLoginPopupJson(req) if err := Config.SaveJson(staticJson, "LoginDialog"); err != nil { return errors.WithStack(err) } return nil } func (This *configService) buildLoginPopupJson(list []model.TLoginBulletBox) []model.LoginPopupStatic { statics := make([]model.LoginPopupStatic, 0, len(list)) for _, box := range list { box.Desc = utils.Concat(box.Name, ":", box.Desc) statics = append(statics, box.LoginPopupStatic) } return statics }