...
 
Commits (197)
package cp_e
type CpAchievement int
const (
CpAchievementLevel CpAchievement = 1 // 等级
CpAchievementVisitors CpAchievement = 2 // 空间访问人数
CpAchievementMonthRank CpAchievement = 3 // 月榜最高
CpAchievementWeekRank CpAchievement = 4 // 周榜最高
CpAchievementDayRank CpAchievement = 5 // 日榜最高
)
package cp_e
type AnniversaryItemType int
const (
AnniversaryItemTypeNormal AnniversaryItemType = 0 // 普通类型
AnniversaryItemTypeAvatar AnniversaryItemType = 1 // 头像类型
AnniversaryItemTypeAnniversary AnniversaryItemType = 2 // 纪念日类型(一年一度,如生日/结婚纪念日)
)
package cp_e
import "git.hilo.cn/hilo-common/resource/mysql"
type CpInviteStatus mysql.Type
type CpCancelStatus mysql.Type
const (
//新用户
CpRelationInviteDiamond = 7777
//1.未接受2.已接受3.拒接导致退费4.过期导致退费
CpInvite CpInviteStatus = 1
CpInviteAccept CpInviteStatus = 2
CpInviteRefuse CpInviteStatus = 3
CpInviteExpired CpInviteStatus = 4
//1.未处理2.发起者已撤销3.对方已确认4.到期自动确认
CpCancel CpCancelStatus = 1
CpCancelRevoke CpCancelStatus = 2
CpCancelAccept CpCancelStatus = 3
CpCancelAcceptAuto CpCancelStatus = 4
CpConfessionGiftId = 3481 // cp礼物id
CpMaleHeadwearId = 2551 // cp绑定成功后赠送的头饰-男
CpFemaleHeadwearId = 2561 // cp绑定成功后赠送的头饰-女
)
package cp_e
import "git.hilo.cn/hilo-common/resource/mysql"
const (
EffectDays = 30 // 30天有效期
CpHeadwearId = 2571
)
type CpLevel int
const (
CpLevel0 CpLevel = 0 // 无称号
CpLevel1 CpLevel = 1 // 恋爱CP
CpLevel2 CpLevel = 2 // 甜蜜CP
CpLevel3 CpLevel = 3 // 忠诚CP
CpLevel4 CpLevel = 4 // 炽热CP
CpLevel5 CpLevel = 5 // 荣耀CP
CpLevelMax = CpLevel5
)
var (
// cp等级积分
CpLevelPoints = map[CpLevel]mysql.Num{
CpLevel0: 0,
CpLevel1: 200000,
CpLevel2: 800000,
CpLevel3: 1000000,
CpLevel4: 3000000,
CpLevel5: 10000000,
}
// cp等级icon // todo ui
CpLevelIcon = map[CpLevel]string{
CpLevel0: "icon0.png",
CpLevel1: "icon1.png",
CpLevel2: "icon2.png",
CpLevel3: "icon3.png",
CpLevel4: "icon4.png",
CpLevel5: "icon5.png",
}
// cp等级称号
CpLevelTitle = map[CpLevel]uint{
CpLevel1: 252,
CpLevel2: 253,
CpLevel3: 254,
CpLevel4: 255,
CpLevel5: 256,
}
// cp特权名称
CpPrivilegeNameMsgId = map[CpPrivilege]uint{
CpPrivilegeSpace: 234,
CpPrivilegeBanner: 235,
CpPrivilegeMedal: 236,
CpPrivilegeCert: 237,
CpPrivilegeRoomEffect: 238,
CpPrivilegeHeadwear: 239,
CpPrivilegeActiveProfile: 240,
CpPrivilegeMicEffect: 241,
}
// cp特权描述
CpPrivilegeDescMsgId = map[CpPrivilege]uint{
CpPrivilegeSpace: 264,
CpPrivilegeBanner: 265,
CpPrivilegeMedal: 266,
CpPrivilegeCert: 267,
CpPrivilegeRoomEffect: 268,
CpPrivilegeHeadwear: 269,
CpPrivilegeActiveProfile: 270,
CpPrivilegeMicEffect: 271,
}
// cp特权icon // todo ui
CpPrivilegeIcon = map[CpPrivilege]string{
CpPrivilegeSpace: "icon_p_1.png",
CpPrivilegeBanner: "icon_p_2.png",
CpPrivilegeMedal: "icon_p_3.png",
CpPrivilegeCert: "icon_p_4.png",
CpPrivilegeRoomEffect: "icon_p_5.png",
CpPrivilegeHeadwear: "icon_p_6.png",
CpPrivilegeActiveProfile: "icon_p_7.png",
CpPrivilegeMicEffect: "icon_p_8.png",
}
)
type CpPrivilege int
const (
CpPrivilegeSpace CpPrivilege = 1 // 空间
CpPrivilegeBanner CpPrivilege = 2 // 横幅
CpPrivilegeMedal CpPrivilege = 3 // 等级勋章
CpPrivilegeCert CpPrivilege = 4 // 证书
CpPrivilegeRoomEffect CpPrivilege = 5 // 进场特效
CpPrivilegeHeadwear CpPrivilege = 6 // 头像头饰
CpPrivilegeActiveProfile CpPrivilege = 7 // 动态资料卡
CpPrivilegeMicEffect CpPrivilege = 8 // 麦位特效
)
package gift_e
import "git.hilo.cn/hilo-common/resource/mysql"
type GiftOperateSceneType mysql.Type
const (
//匹配声网中场景
MatchVedioSceneType GiftOperateSceneType = 1
// 私聊
PriveChatSceneType GiftOperateSceneType = 2
//1对1视频
VideoSceneType GiftOperateSceneType = 3
//群组
GroupSceneType GiftOperateSceneType = 4
)
type ResGiftAvatarType = mysql.Type
const (
SendGiftCpGiftAvatarType ResGiftAvatarType = 1 //周CP
MonthlyWealthGiftAvatarType ResGiftAvatarType = 2 //月冠财富榜
MonthlyCharmGiftAvatarType ResGiftAvatarType = 3 //月冠魅力榜
MonthlyPayGiftAvatarType ResGiftAvatarType = 4 //月冠充值榜
WeekStarGiftAvatarType ResGiftAvatarType = 5 //周星榜
CountryStarGiftAvatarType ResGiftAvatarType = 6 // 国家之星
)
type GiftPrivateRecordType = mysql.Type
const (
PrivateRecord GiftPrivateRecordType = 1
VideoTradeUnion GiftPrivateRecordType = 2
PrivateRecordBag GiftPrivateRecordType = 3
)
type GiftColumnType = uint16
const (
GiftColumnGift GiftColumnType = 1 // 礼物
GiftColumnRomance GiftColumnType = 2 // 浪漫
GiftColumnCountry GiftColumnType = 3 // 国家
GiftColumnCustom GiftColumnType = 4 // 定制
)
type GiftTagType = uint16
const (
GiftTagMedal GiftTagType = 1 // 勋章礼物
GiftTagWeeklyStar GiftTagType = 2 // 周星礼物
)
type GiftEntryType = uint16
const (
GiftEntryWeeklyStar GiftEntryType = 1 // 周星活动入口
GiftEntryWeeklyCp GiftEntryType = 2 // 周CP活动入口
GiftEntryMedal GiftEntryType = 3 // 勋章激活动入口
GiftEntryCountryStar GiftEntryType = 4 // 国家之星活动入口
)
......@@ -5,55 +5,16 @@ import "git.hilo.cn/hilo-common/resource/mysql"
type MsgIdType = uint
const (
DEFAULT_LANG = "en"
DefaultLang = "en"
)
type ResMedalType = mysql.Type
const (
Wealth ResMedalType = 1
Charm ResMedalType = 2
LoveForAll ResMedalType = 3
StartForAll ResMedalType = 4
MoonForAll ResMedalType = 5
MarryMe ResMedalType = 6
RoomRocket ResMedalType = 7
Actity ResMedalType = 8
FruitKing ResMedalType = 9
BoxKing ResMedalType = 10
Helicopter ResMedalType = 11
Roadster ResMedalType = 12
Watermelon ResMedalType = 13
Kiss ResMedalType = 14
Love ResMedalType = 15
Chick ResMedalType = 16
SportsCar ResMedalType = 17
Rocket ResMedalType = 18
Tower ResMedalType = 19
Eagle ResMedalType = 20
Lion ResMedalType = 21
Vacation ResMedalType = 22
RomanticNight ResMedalType = 23
SweetCouple ResMedalType = 24
Castle ResMedalType = 25
WeddingCar ResMedalType = 26
VideoChat ResMedalType = 27
)
type ResMedalScope = mysql.Type
const (
//私有,只能时管理人发放
Private ResMedalScope = 1
//公有,自己获取
Public ResMedalScope = 2
)
type ResNameplateType = mysql.Type
type ResNameplateObtainType = mysql.Type
type ResNameplateScope = mysql.Type
type ResUserBag = mysql.Type
type ResPropertyAvatarType = mysql.Type
const (
ResUserBagGift ResUserBag = 1 // 背包道具-礼物
......
package cp_corn
import (
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/utils"
"github.com/robfig/cron"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/diamond_m"
"time"
)
// cp邀请、解除到期结算
func CpInviteCancelInit() {
if !config.IsMaster() {
return
}
mylogrus.MyLog.Infof("CpInviteCancelInit")
// 每2min监测一次
c := cron.New()
spec := "0 */2 * * * *"
if !config.AppIsRelease() {
spec = "0 */1 * * * ?" // 测服每1分钟
}
_ = c.AddFunc(spec, func() {
defer utils.CheckGoPanic()
model := domain.CreateModelNil()
// 获取超过24小时没被处理的cp邀请
inviteList, err := cp_m.GetCpInviteByTime(model, time.Now().AddDate(0, 0, -1))
if err != nil {
model.Log.Errorf("CpInviteCancelInit err:%v", err)
return
}
for _, v := range inviteList {
model.Log.Infof("CpInviteCancelInit invite:%+v", v)
err = model.Transaction(func(model *domain.Model) error {
// 更新邀请记录
err = cp_m.UpdateStatusCpInvite(model, v.Id, cp_e.CpInviteExpired)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
// 退费
err = diamond_m.ChangeDiamondAccountDetail(model, diamond_e.CpInviteRefund, v.Id, v.UserId, v.DiamondNum)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CpInviteCancelInit invite:%+v, err:%v", v, err)
return
}
time.Sleep(time.Millisecond * 10)
}
// 获取超过24小时没被处理的cp解除申请
cancelList, err := cp_m.GetCpCancelByTime(model, time.Now().AddDate(0, 0, -1))
if err != nil {
model.Log.Errorf("CpInviteCancelInit err:%v", err)
return
}
for _, v := range cancelList {
model.Log.Infof("CpInviteCancelInit cancel:%+v", v)
err = model.Transaction(func(model *domain.Model) error {
// 更新解除记录
err = cp_m.UpdateStatusCpCancel(model, v.Id, cp_e.CpCancelAcceptAuto)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
// 删除cp关系表的记录
err = cp_m.DelCpRelation(model, v.UserId, v.RecUserId)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CpInviteCancelInit cancel:%+v, err:%v", v, err)
return
}
time.Sleep(time.Millisecond * 10)
}
})
c.Start()
}
package cp_cron
import (
"git.hilo.cn/hilo-common/_const/enum/msg_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"github.com/robfig/cron"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/msg_m"
"hilo-user/domain/model/user_m"
)
// 纪念日
type CpAnniversaryNoticeMsg struct {
Identifier string `json:"identifier"`
Content string `json:"content"`
Timestamp int64 `json:"timestamp"`
}
func CpAnniversaryNotice() {
c := cron.New()
// 1小时操作一次
spec := "0 0 */1 * * ?"
if !config.AppIsRelease() {
// 测服1分钟
spec = "0 * * * * ?"
}
_ = c.AddFunc(spec, func() {
var model = domain.CreateModelNil()
anniversary := cp_m.GetNeedRemindCpAnniversary(model)
if len(anniversary) <= 0 {
return
}
var userIds []uint64
for _, v := range anniversary {
userIds = append(userIds, v.UserId1)
userIds = append(userIds, v.UserId2)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
model.Log.Errorf("GetUserMapByIds fail:%v", err)
}
for _, v := range anniversary {
content1 := cp_m.GetTranslate(285, users[v.UserId1].Language)
content2 := cp_m.GetTranslate(285, users[v.UserId2].Language)
record1 := msg_m.NewUserRecord(model, v.UserId1, msg_e.CpAnniversaryNotice, content1, 0, "", "", "", "", "")
record2 := msg_m.NewUserRecord(model, v.UserId2, msg_e.CpAnniversaryNotice, content2, 0, "", "", "", "", "")
err1, err2 := record1.Persistent(), record2.Persistent()
if err1 != nil || err2 != nil {
model.Log.Errorf("NewUserRecord fail:%v-%v", err1, err2)
return
}
//if err := tencentyun.BatchSendCustomMsg(model, 1, users[0].ExternalId, []string{users[1].ExternalId}, string(data), "cp纪念日"); err != nil {
// model.Log.Errorf("BatchSendCustomMsg fail:%v", err)
//}
//if err := tencentyun.BatchSendCustomMsg(model, 1, users[1].ExternalId, []string{users[0].ExternalId}, string(data), "cp纪念日"); err != nil {
// model.Log.Errorf("BatchSendCustomMsg fail:%v", err)
//}
if err := cp_m.UpdateCpAnniversaryReminded(model, v.ID); err != nil {
model.Log.Errorf("UpdateCpAnniversaryReminded fail:%v", err)
}
}
})
c.Start()
}
package cp_cron
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"github.com/robfig/cron"
"hilo-user/domain/model/cp_m"
)
func ClearCpExpire() {
c := cron.New()
spec := "0 0 */1 * * ?"
if !config.AppIsRelease() {
spec = "0 * * * * ?"
}
// 1小时清理一次
_ = c.AddFunc(spec, func() {
var model = domain.CreateModelNil()
if err := cp_m.ClearExpireCpPoints(model); err != nil {
model.Log.Errorf("ClearExpireCpPoints fail:%v", err)
}
})
c.Start()
}
package cron
import (
"git.hilo.cn/hilo-common/resource/config"
"hilo-user/corn/cp_corn"
"hilo-user/cron/cp_cron"
"hilo-user/cron/gift_cron"
)
func Init() {
if !config.IsMaster() {
return
}
gift_cron.SendGiftEventInit() // 礼物消息
gift_cron.GiftRemark() // 礼物消息补偿
cp_cron.ClearCpExpire() // 清理过期cp
cp_cron.CpAnniversaryNotice() // cp纪念日
cp_corn.CpInviteCancelInit() // cp邀请、解除到期结算
}
package gift_cron
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"github.com/robfig/cron"
"hilo-user/domain/model/event_m"
)
// 补偿检查mark=2
func GiftRemark() {
c := cron.New()
// 每5分钟
spec := "0 */5 * * * ?"
if !config.AppIsRelease() {
spec = "0 * * * * ?" // 测服1分钟
}
_ = c.AddFunc(spec, func() {
var model = domain.CreateModelNil()
unmarks, err := event_m.FetchUnMarkEvents(model, 10)
if err != nil {
model.Log.Errorf("FetchUnMarkEvents fail:%v", err)
return
}
for _, unmark := range unmarks {
model.Log.Infof("FetchUnMarkEvent start:%v", unmark.ID)
// 重新入库
if err := event_m.AddUnMarkEvent(model, &event_m.EventGiftSend{
Proto: unmark.Proto,
Payload: unmark.Payload,
MarkHiloGroup: unmark.MarkHiloGroup,
MarkHiloUser: unmark.MarkHiloUser,
Mark: unmark.Mark, // 不能影响别的服务的mark状态
}); err != nil {
model.Log.Errorf("FetchUnMarkEvent add unmark fail:%v", err)
continue
}
// 旧的标记已处理
unmark.Model = model
if err := unmark.MarkDone(); err != nil {
model.Log.Errorf("FetchUnMarkEvent mark fail:%v", err)
}
model.Log.Infof("FetchUnMarkEvent success:%v", unmark.ID)
}
})
c.Start()
}
package gift_cron
import (
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"hilo-user/domain/service/event_s"
"time"
)
// 送礼事件
func SendGiftEventInit() {
mylogrus.MyLog.Infof("SendGiftEventInit")
go func() {
ticker := time.NewTicker(time.Millisecond * 500)
defer ticker.Stop()
for {
select {
case <-ticker.C:
//start := time.Now()
myCtx := mycontext.CreateMyContext(nil)
// 消费送礼事件
if err := event_s.NewGiftSendEventService(myCtx).Consume(); err != nil {
myCtx.Log.Errorf("eventServcie consume fail:%v", err)
} else {
//myCtx.Log.Infof("eventServcie consume success,cost:%v", time.Now().Sub(start))
}
}
}
}()
}
package cp_cv
import (
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/user_cv"
)
// cp信息
type CvCpBase struct {
UserInfo user_cv.UserTiny `json:"userInfo"` // 用户信息
CpUserInfo user_cv.UserTiny `json:"cpUserInfo,omitempty"` // cp用户信息
}
type CvCpAnniversary struct {
Type cp_e.AnniversaryItemType `json:"type"` // 列表类型 0:普通 1:头像
CpInfo *CvCpBase `json:"cpInfo,omitempty"` // cp信息,type=1(头像)时候用到
Id uint64 `json:"id"` // 记录id
Content string `json:"content"` // 纪念日内容
OriginTimestamp int64 `json:"originTimestamp"` // 纪念日的时间
Timestamp int64 `json:"timestamp"` // 下次纪念日时间戳
IsRemind bool `json:"isRemind"` // 是否提醒
CanDel bool `json:"canDel"` // 能否删除
IsTop bool `json:"isTop"` // 是否置顶
}
package cp_cv
import "hilo-user/cv/user_cv"
// cp信息
type CvCp struct {
CpUserInfo *user_cv.CvUserBase `json:"cpUserInfo"` // cp用户信息
CpLevel CvCpLevel `json:"cpLevel"` // cp等级
MyPrivilegeList []CvPrivilege `json:"myPrivilegeList"` // 等级特权
CreatedUnix int64 `json:"createdUnix"` // cp创建时间
CpDays int `json:"cpDays"` // cp天数
}
// cp关系
type CvCpRelation struct {
CpId uint64 `json:"cpId"`
UserId uint64 `json:"userId"`
CpUserId uint64 `json:"cpUserId"`
CpUserAvatar string `json:"cpUserAvatar,omitempty"`
}
package cp_cv
type CheckCpRelationRes struct {
Diamond uint32 `json:"diamond"`
Msg string `json:"msg"`
}
type CheckCpImRes struct {
}
package cp_cv
import (
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/user_cv"
)
type CvCpRank struct {
CpId uint64 `json:"cpId"` // cpId
User1 *user_cv.CvUserBase `json:"user1"` // user1
User2 *user_cv.CvUserBase `json:"user2,omitempty"` // user2
Score uint32 `json:"score"` // 分值
CpLevel CvCpLevel `json:"cpLevel"` // cp等级
Ranking string `json:"ranking"` // 排名
}
type CvCpAchievement struct {
CpId uint64 `json:"cpId"` // cpId
User1 *user_cv.UserTiny `json:"user1"` // user1
User2 *user_cv.UserTiny `json:"user2"` // user2
CpLevel cp_e.CpLevel `json:"cpLevel"` // cpLevel
Type cp_e.CpAchievement `json:"type"` // 成就类型 1:等级 2:空间访问人数 3:月榜最高 4:周榜最高 5:日榜最高
TypeDesc string `json:"typeDesc"` // 成就类型翻译
Score uint32 `json:"score"` // 分值
TimeUnix int64 `json:"timeUnix"` // 达成成就时间戳
}
type CpTops struct {
Day []CvCpRank `json:"day"`
Week []CvCpRank `json:"week"`
}
package cp_cv
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/res_m"
"time"
)
// cp信息
type CvCpInfo struct {
UserInfo *user_cv.UserTiny `json:"userInfo"` // 用户信息
CpUserInfo *user_cv.UserTiny `json:"cpUserInfo,omitempty"` // cp用户信息
CreatedUnix int64 `json:"createdUnix"` // cp创建时间
CpDays int `json:"cpDays"` // cp天数
VisitTimes int64 `json:"visitTimes"` // 空间访问量
ApplyToUnbind bool `json:"applyToUnbind"` // 是否申请撤销cp
}
// cp等级
type CvCpLevel struct {
Level cp_e.CpLevel `json:"level"` // 等级 0:无称号 1:恋爱CP 2:甜蜜CP 3:忠诚CP 4:炽热CP 5:荣耀CP
Points uint32 `json:"points"` // CP值
StartPoints uint32 `json:"startPoints,omitempty"` // 上个等级所需CP值
EndPoints uint32 `json:"endPoints,omitempty"` // 下个等级所需CP值
ExpireAtUnix int64 `json:"expireAtUnix,omitempty"` // 有效期,时间戳
SettlementDate string `json:"settlementDate"` // 等级过期时间
MaxLevel cp_e.CpLevel `json:"maxLevel"` // cp最大的等级
Title string `json:"title,omitempty"` // 称号翻译
}
// 资源等级
type CvResLevel struct {
Level cp_e.CpLevel `json:"level"` // 等级
Icon string `json:"icon"` // 等级icon图
StartPoints uint32 `json:"startPoints"` // 上个等级所需CP值
EndPoints uint32 `json:"endPoints,omitempty"` // 下个等级所需CP值
}
// 特权信息
type CvPrivilege struct {
Type cp_e.CpPrivilege `json:"type"` // 特权id 1:空间 2:横幅 3:等级勋章 4:证书 5:进场特效 6:头像头饰 7:动态资料卡 8:麦位特效
NameMsgId uint `json:"-"` // 名称-翻译id
Name string `json:"name"` // 名称
DescMsgId uint `json:"-"` // 描述-翻译id
Desc string `json:"desc"`
Icon string `json:"icon"` // 图标
CanSwitch bool `json:"canSwitch"` // 能否开关
UserSwitch bool `json:"userSwitch"` // 用户开关
LevelList []cp_e.CpLevel `json:"levelList"` // 特权->level的反向索引
}
// cp空间页
type CvSpace struct {
CpInfo CvCpInfo `json:"cpInfo"` // cp信息
CpLevel CvCpLevel `json:"cpLevel"` // cp等级
ResLevelList []CvResLevel `json:"resLevelList"` // 资源等级列表,无称号/恋爱CP/甜蜜CP/忠诚CP/炽热CP/荣耀CP
PrivilegeList [][]CvPrivilege `json:"privilegeList"` // 等级特权
CpAnniversary []CvCpAnniversary `json:"cpAnniversary"` // 提醒的纪念日
}
var CvResLevelList = []CvResLevel{
{cp_e.CpLevel0, cp_e.CpLevelIcon[cp_e.CpLevel0], cp_e.CpLevelPoints[cp_e.CpLevel0], cp_e.CpLevelPoints[cp_e.CpLevel1]},
{cp_e.CpLevel1, cp_e.CpLevelIcon[cp_e.CpLevel1], cp_e.CpLevelPoints[cp_e.CpLevel1], cp_e.CpLevelPoints[cp_e.CpLevel2]},
{cp_e.CpLevel2, cp_e.CpLevelIcon[cp_e.CpLevel2], cp_e.CpLevelPoints[cp_e.CpLevel2], cp_e.CpLevelPoints[cp_e.CpLevel3]},
{cp_e.CpLevel3, cp_e.CpLevelIcon[cp_e.CpLevel3], cp_e.CpLevelPoints[cp_e.CpLevel3], cp_e.CpLevelPoints[cp_e.CpLevel4]},
{cp_e.CpLevel4, cp_e.CpLevelIcon[cp_e.CpLevel4], cp_e.CpLevelPoints[cp_e.CpLevel4], cp_e.CpLevelPoints[cp_e.CpLevel5]},
{cp_e.CpLevel5, cp_e.CpLevelIcon[cp_e.CpLevel5], cp_e.CpLevelPoints[cp_e.CpLevel5], cp_e.CpLevelPoints[cp_e.CpLevelMax]},
}
var (
CvPrivilege1 = CvPrivilege{cp_e.CpPrivilegeSpace, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeSpace], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeSpace], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeSpace], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeSpace]}
CvPrivilege2 = CvPrivilege{cp_e.CpPrivilegeBanner, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeBanner], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeBanner], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeBanner], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeBanner]}
CvPrivilege3 = CvPrivilege{cp_e.CpPrivilegeMedal, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeMedal], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeMedal], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeMedal], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeMedal]}
CvPrivilege4 = CvPrivilege{cp_e.CpPrivilegeCert, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeCert], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeCert], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeCert], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeCert]}
CvPrivilege5 = CvPrivilege{cp_e.CpPrivilegeRoomEffect, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeRoomEffect], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeRoomEffect], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeRoomEffect], true, false, CpPrivilegeLevelList[cp_e.CpPrivilegeRoomEffect]}
CvPrivilege6 = CvPrivilege{cp_e.CpPrivilegeHeadwear, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeHeadwear], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeHeadwear], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeHeadwear], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeHeadwear]}
CvPrivilege7 = CvPrivilege{cp_e.CpPrivilegeActiveProfile, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeActiveProfile], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeActiveProfile], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeActiveProfile], true, false, CpPrivilegeLevelList[cp_e.CpPrivilegeActiveProfile]}
CvPrivilege8 = CvPrivilege{cp_e.CpPrivilegeMicEffect, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeMicEffect], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeMicEffect], "", cp_e.CpPrivilegeIcon[cp_e.CpPrivilegeMicEffect], false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeMicEffect]}
)
var CpLevelPrivilegeList = map[cp_e.CpLevel][]CvPrivilege{
cp_e.CpLevel0: {CvPrivilege1},
cp_e.CpLevel1: {CvPrivilege1, CvPrivilege2, CvPrivilege3, CvPrivilege4},
cp_e.CpLevel2: {CvPrivilege1, CvPrivilege2, CvPrivilege3, CvPrivilege4, CvPrivilege5},
cp_e.CpLevel3: {CvPrivilege1, CvPrivilege2, CvPrivilege3, CvPrivilege4, CvPrivilege5, CvPrivilege6},
cp_e.CpLevel4: {CvPrivilege1, CvPrivilege2, CvPrivilege3, CvPrivilege4, CvPrivilege5, CvPrivilege6, CvPrivilege7},
cp_e.CpLevel5: {CvPrivilege1, CvPrivilege2, CvPrivilege3, CvPrivilege4, CvPrivilege5, CvPrivilege6, CvPrivilege7, CvPrivilege8},
}
var CpPrivilegeLevelList = map[cp_e.CpPrivilege][]cp_e.CpLevel{
cp_e.CpPrivilegeSpace: {cp_e.CpLevel0, cp_e.CpLevel1, cp_e.CpLevel2, cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeBanner: {cp_e.CpLevel1, cp_e.CpLevel2, cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeMedal: {cp_e.CpLevel1, cp_e.CpLevel2, cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeCert: {cp_e.CpLevel1, cp_e.CpLevel2, cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeRoomEffect: {cp_e.CpLevel2, cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeHeadwear: {cp_e.CpLevel3, cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeActiveProfile: {cp_e.CpLevel4, cp_e.CpLevel5},
cp_e.CpPrivilegeMicEffect: {cp_e.CpLevel5},
}
func CopyCpLevelPrivilegeList(Level cp_e.CpLevel, lang string) []CvPrivilege {
privileges := make([]CvPrivilege, len(CpLevelPrivilegeList[Level]))
copy(privileges, CpLevelPrivilegeList[Level])
for i, v := range privileges {
privileges[i].Name = GetTranslate(v.NameMsgId, lang)
privileges[i].Desc = GetTranslate(v.DescMsgId, lang)
}
return privileges
}
var translateCache = gcache.New(1000).LRU().Build()
func GetTranslate(msgId uint, lang string) string {
key := fmt.Sprintf("%v-%v", msgId, lang)
if data, err := translateCache.Get(key); err == nil {
return data.(string)
}
if resMul, _ := res_m.GetResMultiTextBy(mysql.Db, msgId, lang); resMul != nil {
_ = translateCache.SetWithExpire(key, resMul.Content, time.Hour)
return resMul.Content
}
return "default"
}
package headwear_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"strconv"
"time"
)
type CvHeadwear struct {
Id uint64 `json:"id"`
Using bool `json:"using"`
PicUrl mysql.Str `json:"picUrl"`
EffectUrl mysql.Str `json:"effectUrl"`
TimeLeft int64 `json:"timeLeft"` // 离到期还有多少秒(过期则是负数)
}
type CvHeadwearDiamond struct {
Id uint64 `json:"id"`
PicUrl string `json:"picUrl"`
EffectUrl string `json:"effectUrl"`
DiamondNum uint32 `json:"diamondNum"`
Second uint32 `json:"second"`
Days string `json:"days"`
}
func GetCvHeadwearDiamond(pageSize int, pageIndex int) ([]CvHeadwearDiamond, error) {
headwearDiamonds := []CvHeadwearDiamond{}
if err := mysql.Db.Raw("SELECT d.id, r.pic_url, r.effect_url, d.`second`, d.diamond_num from res_headwear r, res_headwear_diamond d where r.id = d.res_headwear_id and d.`status` = ? ORDER BY d.diamond_num asc LIMIT ?, ?", mysql.USER, (pageIndex-1)*pageSize, pageSize).Scan(&headwearDiamonds).Error; err != nil {
return nil, myerr.WrapErr(err)
}
for i, _ := range headwearDiamonds {
headwearDiamonds[i].Days = strconv.FormatUint(uint64(headwearDiamonds[i].Second/(24*60*60)), 10)
}
return headwearDiamonds, nil
}
func GetHeadwearList(db *gorm.DB, userId uint64) ([]CvHeadwear, error) {
rows := make([]user_m.UserHeadwear, 0)
if err := db.Where(&user_m.UserHeadwear{
UserId: userId,
}).Where("end_time >= ?", time.Now()).Order("`using` DESC, updated_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
resHwMap, err := res_m.GetResHeadwearMap(db)
if err != nil {
return nil, myerr.WrapErr(err)
}
result := make([]CvHeadwear, 0)
now := time.Now()
hasUsing := false
for _, i := range rows {
// TODO: 没过期并且有设置using的,才算是,因为写入方不维护using状态的更新
isUsing := i.Using == headwear_e.YesUsing && i.EndTime.After(now)
result = append(result, CvHeadwear{
Id: i.HeadwearId,
PicUrl: resHwMap[i.HeadwearId].PicUrl,
EffectUrl: resHwMap[i.HeadwearId].EffectUrl,
Using: isUsing,
TimeLeft: i.EndTime.Unix() - now.Unix(),
})
if isUsing {
hasUsing = true
}
}
// 如果没有一个using,则找第一个没过期的充当
if ! hasUsing {
for i, e := range result {
if e.TimeLeft > 0 {
result[i].Using = true
break
}
}
}
return result, nil
}
func GetCvHeadwear(userId uint64) (*CvHeadwear, error) {
userHeadwear := user_m.UserHeadwear{}
if err := mysql.Db.Model(&user_m.UserHeadwear{}).Where(&user_m.UserHeadwear{
UserId: userId,
}).Where("end_time >= ?", time.Now()).Order("`using` DESC, updated_time DESC").First(&userHeadwear).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resHeadwear := res_m.ResHeadwear{}
if err := mysql.Db.Model(&res_m.ResHeadwear{}).First(&resHeadwear, userHeadwear.HeadwearId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
return &CvHeadwear{
Id: userHeadwear.HeadwearId,
PicUrl: resHeadwear.PicUrl,
EffectUrl: resHeadwear.EffectUrl,
Using: userHeadwear.Using == headwear_e.YesUsing,
}, nil
}
func BatchGetCvHeadwears(userIds []uint64) (map[uint64]CvHeadwear, error) {
if len(userIds) == 0 {
return map[uint64]CvHeadwear{}, nil
}
rows := make([]user_m.UserHeadwear, 0)
//asc 进行覆盖,保证了updated_time 最大的是最后的输出
if err := mysql.Db.Where("user_id IN ?", userIds).Where("end_time >= ?", time.Now()).
Order("`using` ASC, updated_time ASC").Find(&rows).Error; err != nil {
return nil, err
}
//
resHeadwearIds := make([]uint64, 0, len(rows))
for i, _ := range rows {
resHeadwearIds = append(resHeadwearIds, rows[i].HeadwearId)
}
//获取头饰资源,然后转换成map结构
resHeadwearMap := map[uint64]res_m.ResHeadwear{}
resHeadwears := []res_m.ResHeadwear{}
if err := mysql.Db.Where("id IN ?", resHeadwearIds).Find(&resHeadwears).Error; err != nil {
return nil, err
}
for i, _ := range resHeadwears {
resHeadwearMap[resHeadwears[i].ID] = resHeadwears[i]
}
result := make(map[uint64]CvHeadwear, 0)
for _, r := range rows {
headwear, flag := resHeadwearMap[r.HeadwearId]
if flag {
result[r.UserId] = CvHeadwear{
Id: headwear.ID,
PicUrl: headwear.PicUrl,
EffectUrl: headwear.EffectUrl,
Using: r.Using == headwear_e.YesUsing,
}
}
}
return result, nil
}
package medal_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/domain/model/res_m"
"sort"
)
type CvMedal struct {
Id uint32 `json:"id"`
PicUrl mysql.Str `json:"picUrl"`
EffectUrl mysql.Str `json:"effectUrl"`
}
type ReturnGroupMedal struct {
PicUrl string `json:"picUrl"`
SvgaUrl string `json:"svgaUrl"`
}
type PicElement struct {
PicUrl string `json:"picUrl"`
SvgaUrl string `json:"svgaUrl"`
}
func GetMedalInfoMap(db *gorm.DB, medals map[uint64][]uint32) (map[uint64][]uint32, map[uint64][]CvMedal, error) {
resMedals, err := res_m.MedalGetAllMap(db)
if err != nil {
return nil, nil, err
}
medalIds := make(map[uint64][]uint32)
medalMap := make(map[uint64][]CvMedal, 0)
// 只选择合法的勋章
for u, i := range medals {
medalIds[u] = make([]uint32, 0)
medalMap[u] = make([]CvMedal, 0)
for _, j := range i {
if e, ok := resMedals[j]; ok {
medalIds[u] = append(medalIds[u], j)
medalMap[u] = append(medalMap[u], CvMedal{
Id: j,
PicUrl: e.PicUrl,
EffectUrl: e.SvgaUrl,
})
}
}
// 按照勋章排序
sort.Slice(medalIds[u], func(i, j int) bool {
return resMedals[medalIds[u][i]].Sort < resMedals[medalIds[u][j]].Sort
})
sort.Slice(medalMap[u], func(i, j int) bool {
return resMedals[medalMap[u][i].Id].Sort < resMedals[medalMap[u][j].Id].Sort
})
}
return medalIds, medalMap, nil
}
package noble_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/domain/model/noble_m"
"hilo-user/myerr"
"time"
)
type NobleConfig struct {
Level uint16 `json:"level"` // 贵族等级
PurchasePrice uint32 `json:"purchasePrice"` // 购买价格
RenewalPrice uint32 `json:"renewalPrice"` // 续费价格
Duration uint16 `json:"duration"` // 有效期(天)
PicUrl string `json:"picUrl"` // 大图url
DailyGold uint `json:"dailyGold"` // 每日登录领取的金币
RideId uint64 `json:"rideId"` // 赠送的勋章ID
HeaddressId uint64 `json:"headdressId"` // 赠送的头饰ID
Privileges []int `json:"privileges"` // 权益列表
}
type NobleInfo struct {
Level uint16 `json:"level"` // 等级
EndTime int64 `json:"endTime"` // 截止时间
RemainTime int64 `json:"remainTime"` // 还有多久(秒)过期,可以是负数
Price uint32 `json:"price"` // 购买或续费价格
}
type CvNoble struct {
Level uint16 `json:"level"`
EndTime int64 `json:"endTime"`
}
func GetCvNoble(userId uint64) (CvNoble, error) {
userNoble := noble_m.UserNoble{}
if err := mysql.Db.Model(&noble_m.UserNoble{}).Where(&noble_m.UserNoble{
UserId: userId,
}).Where("end_time > ?", time.Now()).Order("level desc").First(&userNoble).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return CvNoble{
Level: 0,
EndTime: 0,
}, nil
} else {
return CvNoble{
Level: 0,
EndTime: 0,
}, myerr.WrapErr(err)
}
} else {
return CvNoble{
Level: userNoble.Level,
EndTime: userNoble.EndTime.Unix(),
}, nil
}
}
func GetCvNobles(userIds []uint64) (map[uint64]CvNoble, error) {
if len(userIds) == 0 {
return map[uint64]CvNoble{}, nil
}
var userNobles []noble_m.UserNoble
if err := mysql.Db.Model(&noble_m.UserNoble{}).Where("user_id in (?)", userIds).Where("end_time > ?", time.Now()).Order("level asc").Find(&userNobles).Error; err != nil {
return nil, err
}
userNobleMap := map[uint64]noble_m.UserNoble{}
for i, _ := range userNobles {
userNobleMap[userNobles[i].UserId] = userNobles[i]
}
result := map[uint64]CvNoble{}
for _, r := range userIds {
userNoble, flag := userNobleMap[r]
if flag {
result[r] = CvNoble{
Level: userNoble.Level,
EndTime: userNoble.EndTime.Unix(),
}
} else {
result[r] = CvNoble{
Level: 0,
EndTime: 0,
}
}
}
return result, nil
}
package property_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"strconv"
"time"
)
type CvProperty struct {
Id uint64 `json:"id"`
PicUrl mysql.Str `json:"picUrl"`
EffectUrl mysql.Str `json:"effectUrl"`
Using bool `json:"using"`
TimeLeft int64 `json:"timeLeft"` // 离到期还有多少秒(过期则是负数)
SenderAvatar string `json:"senderAvatar"`
ReceiverAvatar string `json:"receiverAvatar"`
}
type CvPropertyDiamond struct {
Id uint64 `json:"id"`
PicUrl string `json:"picUrl"`
EffectUrl string `json:"effectUrl"`
DiamondNum uint32 `json:"diamondNum"`
Second uint32 `json:"second"`
Days string `json:"days"`
}
func GetCvPropertyDiamond(pageSize int, pageIndex int) ([]CvPropertyDiamond, error) {
propertyDiamonds := []CvPropertyDiamond{}
if err := mysql.Db.Raw("select d.id, r.pic_url, r.effect_url, d.`second`, d.diamond_num from res_property r, res_property_diamond d where r.id = d.res_property_id and d.`status` = ? ORDER BY d.diamond_num ASC LIMIT ?, ?", mysql.USER, (pageIndex-1)*pageSize, pageSize).Scan(&propertyDiamonds).Error; err != nil {
return nil, myerr.WrapErr(err)
}
for i, _ := range propertyDiamonds {
propertyDiamonds[i].Days = strconv.FormatUint(uint64(propertyDiamonds[i].Second/(24*60*60)), 10)
}
return propertyDiamonds, nil
}
func GetPropertyById(resPropertyId mysql.ID) (CvProperty, error) {
resProperty := res_m.ResProperty{}
if err := mysql.Db.Model(&res_m.ResProperty{}).First(&resProperty, resPropertyId).Error; err != nil {
return CvProperty{}, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
if err != nil {
return CvProperty{}, err
}
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := mysql.Db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return CvProperty{}, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[resProperty.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
return CvProperty{
Id: resProperty.ID,
PicUrl: resProperty.PicUrl,
EffectUrl: resProperty.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}, nil
}
func GetPropertyAll(db *gorm.DB) (map[uint64]CvProperty, error) {
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := map[uint64]CvProperty{}
for _, r := range properties {
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[r.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result[r.ID] = CvProperty{
Id: r.ID,
PicUrl: r.PicUrl,
EffectUrl: r.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}
}
return result, nil
}
func GetPropertyList(db *gorm.DB, userId uint64) ([]CvProperty, error) {
rows := make([]user_m.UserProperty, 0)
if err := db.Where(&user_m.UserProperty{
UserId: userId,
}).Order("`using` DESC, updated_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := make([]CvProperty, 0)
now := time.Now()
hasUsing := false
for _, i := range rows {
// TODO: 没过期并且有设置using的,才算是,因为写入方不维护using状态的更新
isUsing := i.Using == headwear_e.YesUsing && i.EndTime.After(now)
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[i.PropertyId]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result = append(result, CvProperty{
Id: i.PropertyId,
PicUrl: properties[i.PropertyId].PicUrl,
EffectUrl: properties[i.PropertyId].EffectUrl,
Using: isUsing,
TimeLeft: i.EndTime.Unix() - now.Unix(),
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
})
if isUsing {
hasUsing = true
}
}
// 如果没有一个using,则找第一个没过期的充当
if !hasUsing {
for i, e := range result {
if e.TimeLeft > 0 {
result[i].Using = true
break
}
}
}
return result, nil
}
type PropertyExt struct {
Id uint64
PicUrl mysql.Str
EffectUrl mysql.Str
Using bool
TimeLeft int64 // 离到期还有多少秒(过期则是负数)
SenderAvatar string
ReceiverAvatar string
}
func GetExtendedProperty(db *gorm.DB) (map[uint64]PropertyExt, error) {
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := map[uint64]PropertyExt{}
for _, r := range properties {
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[r.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result[r.ID] = PropertyExt{
Id: r.ID,
PicUrl: r.PicUrl,
EffectUrl: r.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}
}
return result, nil
}
......@@ -5,14 +5,22 @@ import (
)
type UserBag struct {
BagId mysql.ID `json:"bagId"` // 背包id
ResType mysql.Type `json:"resType"` // 道具类型 1:礼物道具
ResId mysql.ID `json:"resId"` // 道具资源id
GiftId mysql.ID `json:"giftId"` // 道具的礼物id
Name string `json:"name"` // 资源名称
DiamondNum mysql.Num `json:"diamondNum"` // 钻石数量
IconUrl string `json:"iconUrl"` // icon url
SvgaUrl string `json:"svgaUrl"` // svga url
Count mysql.Num `json:"count"` // 拥有数量
RemainDays int `json:"remainDays"` // 有效天数
BagId mysql.ID `json:"bagId"` // 背包id
ResType mysql.Type `json:"resType"` // 道具类型 1:礼物道具
ResId mysql.ID `json:"resId"` // 道具资源id
GiftId mysql.ID `json:"giftId"` // 道具的礼物id
Name string `json:"name"` // 资源名称
DiamondNum mysql.Num `json:"diamondNum"` // 钻石数量
IconUrl string `json:"iconUrl"` // icon url
SvgaUrl string `json:"svgaUrl"` // svga url
Count mysql.Num `json:"count"` // 拥有数量
RemainDays int `json:"remainDays"` // 有效天数
TextStyleList []*TextStyle `json:"textStyleList"` // 文本样式
}
type TextStyle struct {
TextColor string `json:"textColor"` //文本颜色
TextSize float32 `json:"textSize"` //文本字体大小
IsBold bool `json:"isBold"` //是否加粗
TextKey string `json:"textKey"` //替换svga 对象里面的key
}
package user_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"gorm.io/gorm"
"hilo-user/cv/headwear_cv"
"hilo-user/cv/medal_cv"
"hilo-user/cv/noble_cv"
"hilo-user/cv/property_cv"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
)
type UserTiny struct {
Id uint64 `json:"id,omitempty"`
ExternalId string `json:"externalId"`
Avatar string `json:"avatar"`
Nick string `json:"nick"`
Sex uint8 `json:"sex"`
Code string `json:"code"`
Country string `json:"country"`
CountryIcon string `json:"countryIcon"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
}
func UserToTiny(user user_m.User) *UserTiny {
return &UserTiny{
Id: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode(),
}
}
func UserTinyToCvTiny(user *user_m.UserTiny) *UserTiny {
return &UserTiny{
Id: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode,
}
}
//用户基本信息
type CvUserBase struct {
//不会有返回值
Id *mysql.ID `json:"id,omitempty"`
//头像,不存在为nil
Avatar *string `json:"avatar"`
//是否默认头像 true:是 false:不是
DefaultAvatar *bool `json:"defaultAvatar"`
//用户对外ID
ExternalId *string `json:"externalId"`
//昵称,不存在为nil
Nick *string `json:"nick"`
//签名,不存在为nil
Description *string `json:"description"`
//性别 1:男 2:女,不存在为nil
Sex *uint8 `json:"sex"`
//国家,不存在为nil
Country *string `json:"country"`
//国旗图标,不存在为nil
CountryIcon *string `json:"countryIcon"`
//邀请码
Code *string `json:"code"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
IsLogout bool `json:"isLogout"` //是否注销
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
//是否展示年龄, 是本人才有数据,看其他用户均为nil
IsShowAge *uint8 `json:"isShowAge"`
//是否工会成员, 只有是自己查自己,这个才有值,其它全为nil, 20220329 数据开放:原因:产品1对1视频聊天中,公会用户视频需要送礼物。改为: 全部人可以知道是否是公会用户。
IsTradeUnion *bool `json:"isTradeUnion"`
//是否代理管理员, 只有自己查自己的时候才有值,其他情况为nil
IsAgentMgr *bool `json:"isAgentMgr"`
//工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值,
IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"`
//是否VIP用户
IsVip bool `json:"isVip"`
//是否是官方人员
IsOfficialStaff bool `json:"isOfficialStaff"`
//VIP用户过期时间(只有自己查询自己,才返回)
VipExpireTime *int64 `json:"vipExpireTime"`
Svip rpc.CvSvip `json:"svip"` // svip结构,等级+权限
MedalInfo []medal_cv.CvMedal `json:"medalInfo"` // 勋章列表
Headwear *headwear_cv.CvHeadwear `json:"headwear"` // 当前使用的头饰
Ride property_cv.CvProperty `json:"ride"` // 当前使用的座驾
Noble noble_cv.CvNoble `json:"noble"` // 当前的
}
//批量获取用户基本信息
func GetUserBases(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserBase, error) {
if len(userIds) == 0 {
return []*CvUserBase{}, nil
}
var users []user_m.User
if err := mysql.Db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return nil, myerr.WrapErr(err)
}
svips, err := rpc.MGetUserSvip(domain.CreateModelNil(), userIds)
if err != nil {
mylogrus.MyLog.Errorf("MGetUserSvip fail:%v", err)
//return nil, myerr.WrapErr(err)
}
headwearMap, err := headwear_cv.BatchGetCvHeadwears(userIds)
if err != nil {
return nil, err
}
logger := mylogrus.MyLog.WithField("func", "GetUserBases")
medals, err := user_m.BatchGetUserMedalMerge(logger, mysql.Db, userIds)
if err != nil {
return nil, err
}
medals, medalInfo, err := getMedalInfoMap(mysql.Db, medals)
if err != nil {
return nil, err
}
up := user_m.UserProperty{}
rides, err := up.BatchGet(mysql.Db, userIds)
if err != nil {
return nil, err
}
//rp := res_m.ResProperty{}
//properties, err := rp.GetAll(mysql.Db)
properties, err := GetPropertyAll(mysql.Db)
if err != nil {
return nil, err
}
nobles, err := noble_m.BatchGetActiveNoble(domain.CreateModelNil(), userIds)
if err != nil {
return nil, err
}
superManagerMap, err := GetSuperManagerMap(userIds)
if err != nil {
return nil, err
}
cvUserBases := []*CvUserBase{}
for i := 0; i < len(users); i++ {
user := users[i]
invisible := IfLogout(user.LogoutTime)
invisibleAvatar := ""
invisibleNick := user.Code
//for _, p := range svips[user.ID].Privileges {
// if p.Type == 17 && p.UserSwitch { // 神秘人特权
// invisible = true
// invisibleAvatar, invisibleNick = rpc.ReplaceSvipAvatarNick(invisibleAvatar, invisibleNick, svips[user.ID].Privileges)
// }
//}
cvUserBase := &CvUserBase{
Id: &user.ID,
Avatar: StrNil(IfLogoutStr(invisible, invisibleAvatar, user.Avatar)),
DefaultAvatar: &user.DefaultAvatar,
ExternalId: StrToString(&user.ExternalId),
Nick: StrNil(IfLogoutNick(invisible, invisibleNick, user.Nick)),
Description: StrNil(IfLogoutStr(invisible, "", user.Description)),
Sex: TypeToUint8(&user.Sex),
Country: StrNil(user.Country),
CountryIcon: StrNil(user.CountryIcon),
Code: StrToString(&user.Code),
IsPrettyCode: user.IsPrettyCode(),
IsVip: vips[user.ID] != nil,
IsOfficialStaff: superManagerMap[user.ID],
MedalInfo: IfLogoutMedalInfo(invisible, []medal_cv.CvMedal{}, medalInfo[user.ID]),
Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, property_cv.CvProperty{
Id: rides[user.ID],
PicUrl: properties[rides[user.ID]].PicUrl,
EffectUrl: properties[rides[user.ID]].EffectUrl,
Using: true,
SenderAvatar: properties[rides[user.ID]].SenderAvatar,
ReceiverAvatar: properties[rides[user.ID]].ReceiverAvatar,
}),
Noble: noble_cv.CvNoble{
Level: nobles[user.ID].Level,
EndTime: nobles[user.ID].EndTime.Unix(),
},
}
if cvUserBase.Noble.Level <= 0 {
cvUserBase.Noble.EndTime = 0
}
//
if headwear, flag := headwearMap[user.ID]; flag {
cvUserBase.Headwear = IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, &headwear)
}
if user.ID == myUserId {
cvUserBase.VipExpireTime = vips[user.ID]
cvUserBase.IsShowAge = TypeToUint8(&user.IsShowAge)
cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
} else if user.IsShowAge == mysql.OPEN {
cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
}
cvUserBase.Svip = svips[user.ID]
cvUserBases = append(cvUserBases, cvUserBase)
}
return cvUserBases, nil
}
func getMedalInfoMap(db *gorm.DB, medals map[uint64][]uint32) (map[uint64][]uint32, map[uint64][]medal_cv.CvMedal, error) {
resMedals, err := res_m.MedalGetAllMap(db)
if err != nil {
return nil, nil, err
}
medalIds := make(map[uint64][]uint32)
medalMap := make(map[uint64][]medal_cv.CvMedal, 0)
// 只选择合法的勋章
for u, i := range medals {
medalIds[u] = make([]uint32, 0)
medalMap[u] = make([]medal_cv.CvMedal, 0)
for _, j := range i {
if e, ok := resMedals[j]; ok {
medalIds[u] = append(medalIds[u], j)
medalMap[u] = append(medalMap[u], medal_cv.CvMedal{
Id: j,
PicUrl: e.PicUrl,
EffectUrl: e.SvgaUrl,
})
}
}
}
return medalIds, medalMap, nil
}
func GetPropertyAll(db *gorm.DB) (map[uint64]property_cv.CvProperty, error) {
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertyAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
var userIds []uint64
for _, value := range propertyAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := map[uint64]property_cv.CvProperty{}
for _, r := range properties {
var senderAvatar string = ""
var receiverAvatar string = ""
if propertyAvatar, flag := propertyAvatarMap[r.ID]; flag {
if propertyAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertyAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertyAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertyAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result[r.ID] = property_cv.CvProperty{
Id: r.ID,
PicUrl: r.PicUrl,
EffectUrl: r.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}
}
return result, nil
}
func GetSuperManagerMap(userIds []uint64) (map[uint64]bool, error) {
if len(userIds) == 0 {
return map[uint64]bool{}, nil
}
var superManagers []user_m.SuperManager
if err := mysql.Db.Model(&user_m.SuperManager{}).Where("user_id in (?)", userIds).Find(&superManagers).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//转换成map
rs := map[uint64]bool{}
for i, _ := range userIds {
rs[userIds[i]] = false
}
for i, _ := range superManagers {
rs[superManagers[i].UserId] = true
}
return rs, nil
}
func GetUserBaseMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUserBase, error) {
userBases, err := GetUserBases(userIds, myUserId)
if err != nil {
return nil, err
}
//转换成map
mapIdUser := map[mysql.ID]*CvUserBase{}
for i := 0; i < len(userBases); i++ {
mapIdUser[*userBases[i].Id] = userBases[i]
}
return mapIdUser, nil
}
type CvUserTiny struct {
Id uint64 `json:"id,omitempty"`
ExternalId string `json:"externalId"`
Avatar string `json:"avatar"`
Nick string `json:"nick"`
Sex uint8 `json:"sex"`
Code string `json:"code"`
Country string `json:"country"`
CountryIcon string `json:"countryIcon"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
IsLogout bool `json:"isLogout"` //是否注销 true:已经注销, false:没有注销
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
}
package user_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/cv/headwear_cv"
"hilo-user/cv/medal_cv"
"hilo-user/cv/property_cv"
"time"
)
//空字符串转成nil
func StrNil(msg string) *string {
if msg == "" {
return nil
}
return &msg
}
func TypeToUint8(t *mysql.Type) *uint8 {
if *t == 0 {
return nil
} else {
return (*uint8)(t)
}
}
func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 {
if *birthday == 0 {
return nil
}
return (*uint64)(birthday)
}
func NumToUint32(num *mysql.Num) *uint32 {
return (*uint32)(num)
}
func TimeToUint64(t *time.Time) *uint64 {
a := uint64(t.Unix())
return &a
}
func StrToString(str *mysql.Str) *string {
return (*string)(str)
}
func IndexToUint16(i *mysql.Index) *uint16 {
return (*uint16)(i)
}
func IdToUint64(id *mysql.ID) *uint64 {
return (*uint64)(id)
}
func IsInStringList(str string, list []string) bool {
for _, v := range list {
if str == v {
return true
}
}
return false
}
func IfLogoutStr(condition bool, trueVal, falseVal string) string {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutNick(condition bool, code string, nick string) string {
if condition {
return "Hilo No." + code
}
return nick
}
func IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func IfLogoutMedalInfo(condition bool, trueVal, falseVal []medal_cv.CvMedal) []medal_cv.CvMedal {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutRide(condition bool, trueVal, falseVal property_cv.CvProperty) property_cv.CvProperty {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutHeadwear(condition bool, trueVal, falseVal *headwear_cv.CvHeadwear) *headwear_cv.CvHeadwear {
if condition {
return trueVal
}
return falseVal
}
package user_c
import (
"git.hilo.cn/hilo-common/_const/common"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
redisV8 "github.com/go-redis/redis/v8"
"github.com/jinzhu/copier"
"hilo-user/_const/redis_key/user_k"
......@@ -10,6 +12,7 @@ import (
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"time"
)
// 获取用户简要信息
......@@ -96,10 +99,11 @@ func ToUserIdByCode(model *domain.Model, code mysql.Str) (mysql.ID, error) {
// 顺手缓存code->userId
// param user: 已经在上层获取的db User结构
func cacheUserTiny(model *domain.Model, user *user_m.User) error {
userTiny := new(user_m.UserTiny)
if err := copier.Copy(userTiny, user); err != nil {
return err
}
userTiny := ToUserTinyBy(user)
//userTiny := new(user_m.UserTiny)
//if err := copier.Copy(userTiny, user); err != nil {
// return err
//}
// cache externalId->userId
if err := model.Redis.SetEX(model.Context, user_k.GetExternalIdToUidKey(user.ExternalId), user.ID, cache.GetDefaultTTL()).Err(); err != nil {
return err
......@@ -113,3 +117,89 @@ func cacheUserTiny(model *domain.Model, user *user_m.User) error {
}
return nil
}
// 获取用户简要信息
// param userIds 用户id列表
func GetUserTinyMap(model *domain.Model, userIds []mysql.ID, isDefAvatar bool) (map[mysql.ID]*user_m.UserTiny, error) {
redisNoIds := make([]mysql.ID, 0)
res := make(map[mysql.ID]*user_m.UserTiny)
for _, id := range userIds {
userTiny := new(user_m.UserTiny)
key := user_k.GetUserTinyKey(id)
err := cache.GetJSON(model, key, userTiny)
if err != nil && err != redisV8.Nil {
return nil, err
}
if err == redisV8.Nil {
redisNoIds = append(redisNoIds, id)
} else if userTiny.ID > 0 {
res[id] = userTiny
}
}
// 从db中读
users, err := user_m.GetUsers(model, redisNoIds)
if err != nil {
return nil, err
}
for _, u := range users {
userTiny := ToUserTinyBy(u)
err = cacheUserTiny(model, u)
if err != nil {
return nil, err
}
res[userTiny.ID] = userTiny
}
if isDefAvatar {
for _, v := range res {
if len(v.Avatar) <= 0 {
if v.Sex == mysql.MAN {
v.Avatar = utils.MakeFullUrl(common.DefaultAvatarMan)
} else if v.Sex == mysql.WOMAN {
v.Avatar = utils.MakeFullUrl(common.DefaultAvatarWoman)
}
}
}
}
return res, nil
}
func ToUserTinyBy(user *user_m.User) *user_m.UserTiny {
return &user_m.UserTiny{
ID: user.ID,
Avatar: IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar),
ExternalId: user.ExternalId,
Nick: IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick),
Sex: user.Sex,
Code: user.Code,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode(),
IsLogout: IfLogout(user.LogoutTime),
Birthday: BirthdayToUint64(&user.Birthday),
}
}
func IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 {
if *birthday == 0 {
return nil
}
return (*uint64)(birthday)
}
func IfLogoutStr(condition bool, trueVal, falseVal string) string {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutNick(condition bool, code string, nick string) string {
if condition {
return "Hilo No." + code
}
return nick
}
package cp_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
//注册监听
var spaceVisitListen = new(domain.EventBase)
type SpaceVisitEvent struct {
UserId mysql.ID
CpId mysql.ID
UserId1, UserId2 mysql.ID
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddCpSpaceVisitSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(spaceVisitListen, callback)
}
//加入到异步操作中
func AddCpSpaceVisitAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(spaceVisitListen, callback)
}
//领域事件发布
func PublishCpSpaceVisit(model *domain.Model, event interface{}) error {
return domain.PublishEvent(spaceVisitListen, model, event)
}
package gift_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/gift_e"
)
var sendGiftListen = new(domain.EventBase)
// 送礼事件
type SendGiftEvent struct {
SendUserId mysql.ID
ReceiveUserIds []mysql.ID
ResGift EventResGift
GiftOperateIds []mysql.ID
GiftN mysql.Num
SceneType gift_e.GiftOperateSceneType
SceneUid mysql.Str
NoDiamondConsume bool // 不要消费钻石
TotalConsume uint64 // 房间的总消费额
}
type EventResGift struct {
ID mysql.ID
Name mysql.Str
IconUrl mysql.Str
SvgaUrl mysql.Str
MusicUrl mysql.Str
DiamondNum mysql.Num
BeanNum mysql.Num
ReceiveDiamondNum mysql.Num
Second mysql.Num
N mysql.Num
GroupBroadcast bool
Cp bool
Together bool
Status mysql.UserYesNo
GiftType mysql.Type
}
func AddSendGiftEventSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(sendGiftListen, callback)
}
func AddSendGiftEventAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(sendGiftListen, callback)
}
func PublishSendGiftEvent(model *domain.Model, event interface{}) error {
return domain.PublishEvent(sendGiftListen, model, event)
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/cp_e"
"time"
)
type CpAchievement struct {
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
Type cp_e.CpAchievement
Score mysql.Num
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
}
// 更新cp成就
// 单进程操作,先create,后update
func UpdateCpAchievement(model *domain.Model, cpId, userId1, userId2 mysql.ID, Type cp_e.CpAchievement, score mysql.Num) error {
var cpAchievement CpAchievement
if err := model.DB().Model(CpAchievement{}).Where("cp_id = ? AND `type` = ?", cpId, Type).First(&cpAchievement).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("UpdateCpAchievement fail:%v", err)
return err
}
// gorm.ErrRecordNotFound
cpAchievement = CpAchievement{
CpId: cpId,
UserId1: userId1,
UserId2: userId2,
Type: Type,
Score: score,
}
return model.DB().Model(CpAchievement{}).Create(&cpAchievement).Error
}
// update if less than
return model.DB().Model(CpAchievement{}).Where("cp_id = ? AND `type` = ?", cpId, Type).Where("score < ?", score).UpdateColumn("score", score).Error
}
// 获取cp成就
func GetCpAchievements(model *domain.Model) []CpAchievement {
var achievements []CpAchievement
subQuery := model.DB().Table("cp_achievement a").Joins("JOIN cp_relation r ON a.cp_id = r.id").Select("type,MAX(score) AS max_score").Group("type")
if err := model.DB().Model(CpAchievement{}).Joins("INNER JOIN cp_relation r ON cp_id = r.id").Where("(type, score) IN (?)", subQuery).Order("type ASC").Find(&achievements).Error; err != nil {
model.Log.Errorf("GetAchievements fail:%v", err)
}
return achievements
}
package cp_m
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"time"
)
// CpAnniversary cp纪念日
type CpAnniversary struct {
mysql.Entity
Type cp_e.AnniversaryItemType
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
Content string
Timestamp int64
IsRemind bool
LastRemindTime int64
Sort int
}
// 初始化6个cp纪念日
// 1)我们在一起;2)XXX的生日;3)XXX的生日;4)第一次说我爱你;5)第一次亲吻;6)结婚纪念日
func InitCpAnniversary(model *domain.Model, cp CpRelation, lang string) error {
users, err := user_m.GetUserMapByIds(model, []uint64{cp.UserId1, cp.UserId2})
if err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, cp, GetTranslate(259, lang), time.Now().Unix(), true, 100); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeAnniversary, cp, fmt.Sprintf(GetTranslate(260, lang), users[cp.UserId1].Nick), 0, true, 0); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeAnniversary, cp, fmt.Sprintf(GetTranslate(260, lang), users[cp.UserId2].Nick), 0, true, 0); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, cp, GetTranslate(261, lang), 0, true, 0); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, cp, GetTranslate(262, lang), 0, true, 0); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeAnniversary, cp, GetTranslate(263, lang), 0, true, 0); err != nil {
return err
}
return nil
}
var translateCache = gcache.New(1000).LRU().Build()
func GetTranslate(msgId uint, lang string) string {
key := fmt.Sprintf("%v-%v", msgId, lang)
if data, err := translateCache.Get(key); err == nil {
return data.(string)
}
if resMul, _ := res_m.GetResMultiTextBy(mysql.Db, msgId, lang); resMul != nil {
_ = translateCache.SetWithExpire(key, resMul.Content, time.Hour)
return resMul.Content
}
return "default"
}
// 添加cp纪念日
func AddCpAnniversary(model *domain.Model, Type cp_e.AnniversaryItemType, cp CpRelation, content string, ts int64, isRemind bool, sort int) error {
return model.DB().Model(CpAnniversary{}).Create(&CpAnniversary{
CpId: cp.Id,
Type: Type,
UserId1: cp.UserId1,
UserId2: cp.UserId2,
Content: content,
Timestamp: ts,
IsRemind: isRemind,
LastRemindTime: 0,
Sort: sort,
}).Error
}
// 更新cp纪念日
func UpdateCpAnniversary(model *domain.Model, id mysql.ID, content string, ts int64, isRemind bool) error {
updates := map[string]interface{}{
"content": content,
"timestamp": ts,
"is_remind": isRemind,
}
return model.DB().Model(CpAnniversary{}).Where("id = ?", id).Updates(updates).Error
}
func DelCpAnniversary(model *domain.Model, id mysql.ID) error {
return model.DB().Model(CpAnniversary{}).Where("id = ? ", id).Delete(&CpAnniversary{}).Error
}
// 根据用户id获取所有纪念日
func GetAllCpAnniversary(model *domain.Model, userId mysql.ID) []CpAnniversary {
var res []CpAnniversary
relation, exists := GetCpRelation(model, userId)
if !exists {
return res
}
if err := model.DB().Model(CpAnniversary{}).Where("cp_id = ?", relation.Id).Order("`sort` DESC,updated_time DESC,id ASC").Find(&res).Error; err != nil {
model.Log.Errorf("GetAllCpAnniversary fail:%v", err)
}
return res
}
// 获取所有需要提醒的纪念日
func GetNeedRemindCpAnniversary(model *domain.Model) []CpAnniversary {
var rows, res []CpAnniversary
if err := model.DB().Model(CpAnniversary{}).
Where("`timestamp` > 0").
Where("`timestamp` < ?", time.Now().Unix()).
Where("is_remind = 1").
Where("last_remind_time < ?", time.Now().AddDate(-1, 0, 0).Unix()). // 一年前提醒过
Find(&rows).Error; err != nil {
model.Log.Errorf("GetNeedRemindCpAnniversary fail:%v", err)
}
now := time.Now().Unix()
for i, v := range rows {
ts := CalcNextAnniversary(v.Timestamp)
if now > ts {
res = append(res, rows[i])
}
}
return res
}
// 获取cp当天需要提醒的纪念日
func GetUserTodayCpAnniversary(model *domain.Model, cpId mysql.ID) []CpAnniversary {
var rows, res []CpAnniversary
if err := model.DB().Model(CpAnniversary{}).
Where("`timestamp` > 0").
Where("`timestamp` < ?", time.Now().Unix()).
Where("is_remind = 1").
Where("cp_id = ?", cpId).
Find(&rows).Error; err != nil {
model.Log.Errorf("GetUserTodayCpAnniversary fail:%v", err)
}
now := time.Now().Unix()
for i, v := range rows {
ts := CalcNextAnniversary(v.Timestamp)
if now > ts {
res = append(res, rows[i])
}
}
return rows
}
func UpdateCpAnniversaryReminded(model *domain.Model, id mysql.ID) error {
return model.DB().Model(CpAnniversary{}).Where("id = ?", id).Update("last_remind_time", time.Now().Unix()).Error
}
// 计算下一个纪念日
func CalcNextAnniversary(timestamp int64) int64 {
now := time.Now()
// 还没超过一天,不用计算明年的
if now.Unix()-timestamp < 86400 {
return timestamp
}
birthday := time.Unix(timestamp, 0)
// 计算今年的生日日期
thisYearBirthday := time.Date(now.Year(), birthday.Month(), birthday.Day(), birthday.Hour(), birthday.Minute(), birthday.Second(), 0, time.Local)
// 如果今年的生日还未到,则生日日期为今年的生日日期;否则为明年的生日日期
var next time.Time
if thisYearBirthday.After(now) || now.Sub(thisYearBirthday).Seconds() < 86400 {
next = thisYearBirthday
} else {
next = thisYearBirthday.AddDate(1, 0, 0)
}
// 计算时间戳
nextTimestamp := next.Unix()
return nextTimestamp
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
"time"
)
type CpRelation struct {
Id uint64 `json:"id"`
UserId1 uint64 `json:"userId1"`
UserId2 uint64 `json:"userId2"`
CreatedTime time.Time `json:"createdTime"`
}
type CpInvite struct {
Id uint64 `json:"id"`
UserId uint64 `json:"userId"`
InviteUserId uint64 `json:"inviteUserId"`
DiamondNum uint32 `json:"diamondNum"`
Status cp_e.CpInviteStatus `json:"status"`
}
// 发送私信-发起邀请
type CpInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Tip string `json:"tip"`
Sender *user_m.UserTiny `json:"sender"`
MsgType int `json:"msgType"`
MsgId uint64 `json:"msgId"`
}
// 发送私信-接受邀请
type CpAcceptInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Tip string `json:"tip"`
Sender *user_m.UserTiny `json:"sender"`
Receiver *user_m.UserTiny `json:"receiver"`
}
// 发送私信-拒绝邀请
type CpDenyInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Sender *user_m.UserTiny `json:"sender"`
}
type CpCancel struct {
Id uint64 `json:"id"`
UserId uint64 `json:"userId"`
RecUserId uint64 `json:"recUserId"`
Status cp_e.CpCancelStatus `json:"status"`
}
// 发送私信(解除)
type CpCancelMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Tip string `json:"tip"`
Sender *user_m.UserTiny `json:"sender"`
MsgType int `json:"msgType"`
MsgId uint64 `json:"msgId"`
}
// 发送私信-撤销解除、接受解除
type CpDealCancelMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Status uint8 `json:"status"` //1.撤销解除2.接受解除
}
type Cp struct {
Id uint64 `json:"id"`
UserId1 uint64 `json:"userId1"`
UserId2 uint64 `json:"userId2"`
DisconnectSecond int64 `json:"disconnectSecond"`
Score int32 `json:"score"`
DayScore int32 `json:"dayScore"`
PeriodDay string `json:"periodDay"`
WeekScore int32 `json:"weekScore"`
PeriodWeek string `json:"periodWeek"`
MonthScore int32 `json:"monthScore"`
PeriodMonth string `json:"periodMonth"`
Status int8 `json:"status"`
CreatedTime time.Time `json:"createdTime"`
}
func CreateCp(model *domain.Model, userId1, userId2 uint64) (int64, error) {
userIds := []uint64{userId1, userId2}
oldCp := make([]*Cp, 0)
// 这两个人以前是否有旧的cp关系
err := model.DB().Model(Cp{}).Where("status = 1 and user_id1 in (?) and user_id2 in (?)", userIds, userIds).Find(&oldCp).Error
if err != nil {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, err)
return 0, err
}
createdTime := time.Now()
if len(oldCp) > 0 {
// 旧的cp关系,有效的时间给他加回去
oldSecond := time.Duration(time.Now().Unix() - oldCp[0].CreatedTime.Unix() - oldCp[0].DisconnectSecond)
if oldSecond > 0 {
createdTime = createdTime.Add(-1 * time.Second * time.Duration(time.Now().Unix()-oldCp[0].CreatedTime.Unix()-oldCp[0].DisconnectSecond))
}
}
result, err := model.DB().Config.ConnPool.ExecContext(model, "insert into cp_relation(user_id1, user_id2, created_time) select ?,?,? where not exists (select user_id1 from cp_relation where user_id1 in (?,?) or user_id2 in (?,?));", userId1, userId2, createdTime.Format(utils.DATETIME_FORMAT), userId1, userId2, userId1, userId2)
if err != nil {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, err)
return 0, err
}
rowAffected, _ := result.RowsAffected()
if rowAffected <= 0 {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, bizerr.TransactionFailed)
return 0, bizerr.TransactionFailed
}
id, err := result.LastInsertId()
return id, err
}
func GetCp(model *domain.Model, userId uint64) (*CpRelation, error) {
res := new(CpRelation)
err := model.DB().Model(CpRelation{}).Where("user_id1 = ? or user_id2 = ?", userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return res, nil
}
model.Log.Errorf("CreateCp userId:%d, err:%v", userId, err)
return nil, err
}
return res, nil
}
func GetCpInvite(model *domain.Model, userId, userIdInvite uint64, status cp_e.CpInviteStatus) (*CpInvite, error) {
res := new(CpInvite)
err := model.DB().Model(CpInvite{}).Where(CpInvite{UserId: userId, InviteUserId: userIdInvite, Status: status}).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpInvite user1:%d, user2:%d, err:%v", userId, userIdInvite, err)
return nil, err
}
return res, nil
}
func GetCpInviteById(model *domain.Model, id, userId uint64) (*CpInvite, error) {
res := new(CpInvite)
err := model.DB().Model(CpInvite{}).Where(CpInvite{Id: id}).Where("user_id = ? or invite_user_id = ?", userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpInviteById id:%d, err:%v", id, err)
return nil, err
}
return res, nil
}
func CreateCpInvite(model *domain.Model, userId, userIdInvite uint64, diamondNum uint32) (uint64, error) {
cpInvite := CpInvite{UserId: userId, InviteUserId: userIdInvite, DiamondNum: diamondNum, Status: cp_e.CpInvite}
err := model.DB().Model(CpInvite{}).Create(&cpInvite).Error
if err != nil {
model.Log.Errorf("CreateCpInvite user1:%d, user2:%d, diamondNum:%d, err:%v", userId, userIdInvite, diamondNum, err)
return 0, err
}
return cpInvite.Id, nil
}
// userId:发起邀请者
func UpdateStatusCpInvite(model *domain.Model, id uint64, status cp_e.CpInviteStatus) error {
result := model.DB().Exec("update cp_invite set status=? where id=? and status=? limit 1", status, id, cp_e.CpInvite)
if result.Error != nil {
model.Log.Errorf("UpdateStatusCpInvite id:%d, status:%d, err:%v", id, status, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("UpdateStatusCpInvite id:%d, status:%d, err:%v", id, status, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func CreateCpCancel(model *domain.Model, userId, recUserId uint64) (uint64, error) {
cpCancel := CpCancel{UserId: userId, RecUserId: recUserId, Status: cp_e.CpCancel}
err := model.DB().Model(CpCancel{}).Create(&cpCancel).Error
if err != nil {
model.Log.Errorf("CreateCpCancel user1:%d, user2:%d, err:%v", userId, recUserId, err)
return 0, err
}
return cpCancel.Id, nil
}
func GetCpCancel(model *domain.Model, userIds []uint64, status cp_e.CpCancelStatus) (*CpCancel, error) {
res := new(CpCancel)
err := model.DB().Model(CpCancel{}).Where("status = ? and user_id in (?) and rec_user_id in (?)", status, userIds, userIds).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpCancel users:%d, err:%v", userIds, err)
return nil, err
}
return res, nil
}
func GetCpCancelById(model *domain.Model, id, userId uint64) (*CpCancel, error) {
res := new(CpCancel)
err := model.DB().Model(CpCancel{}).Where("id = ? and (user_id = ? or rec_user_id = ?)", id, userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpCancelById id:%d, err:%v", id, err)
return nil, err
}
return res, nil
}
func GetCpCancelWithMe(model *domain.Model, userId uint64, status cp_e.CpCancelStatus) (*CpCancel, error) {
res := new(CpCancel)
err := model.DB().Model(CpCancel{}).Where("status = ? and (user_id = ? or rec_user_id = ?)", status, userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpCancel user1:%d, err:%v", userId, err)
return nil, err
}
return res, nil
}
func UpdateStatusCpCancel(model *domain.Model, id uint64, status cp_e.CpCancelStatus) error {
result := model.DB().Exec("update cp_cancel set status=? where id=? and status=? limit 1", status, id, cp_e.CpCancel)
if result.Error != nil {
model.Log.Errorf("UpdateStatusCpCancel id:%d, status:%d, err:%v", id, status, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("UpdateStatusCpCancel id:%d, status:%d, err:%v", id, status, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func DelCpRelation(model *domain.Model, userId1, userId2 uint64) error {
userIds := []uint64{userId1, userId2}
result := model.DB().Exec("delete from cp_relation where user_id1 in (?) and user_id2 in (?) limit 1;", userIds, userIds)
if result.Error != nil {
model.Log.Errorf("DelCpRelation user1:%d, user2:%d, err:%v", userId1, userId2, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("DelCpRelation user1:%d, user2:%d, err:%v", userId1, userId2, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func GetCpInviteByTime(model *domain.Model, expTime time.Time) ([]*CpInvite, error) {
res := make([]*CpInvite, 0)
err := model.DB().Model(CpInvite{}).Where("status = ? and created_time <= ?", cp_e.CpInvite, expTime.Format(utils.DATETIME_FORMAT)).Find(&res).Error
if err != nil {
model.Log.Errorf("GetCpInviteByTime err:%v", err)
return nil, err
}
return res, nil
}
func GetCpCancelByTime(model *domain.Model, expTime time.Time) ([]*CpCancel, error) {
res := make([]*CpCancel, 0)
err := model.DB().Model(CpCancel{}).Where("status = ? and created_time <= ?", cp_e.CpCancel, expTime.Format(utils.DATETIME_FORMAT)).Find(&res).Error
if err != nil {
model.Log.Errorf("GetCpCancelByTime err:%v", err)
return nil, err
}
return res, nil
}
package cp_m
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/txop/headwear_tx"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-user/_const/enum/cp_e"
"hilo-user/_const/enum/gift_e"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"time"
)
// cp等级
type CpLevel struct {
mysql.Entity
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
Points mysql.Num
Level cp_e.CpLevel
ExpireAt time.Time
}
// cp等级积分明细
type CpLevelDetail struct {
mysql.Entity
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
BefNum mysql.Num
AftNum mysql.Num
Remark string
}
// 获取cp等级
func GetCpLevel(model *domain.Model, cpId mysql.ID) CpLevel {
var level CpLevel
if err := model.DB().Model(CpLevel{}).Where("cp_id = ?", cpId).First(&level).Error; err != nil {
model.Log.Errorf("GetCpLevel fail:%v", err)
}
return level
}
// 批量获取cp等级
func MGetCpLevel(model *domain.Model, cpIds []mysql.ID) map[mysql.ID]CpLevel {
var res = make(map[mysql.ID]CpLevel)
var level []CpLevel
if err := model.DB().Model(CpLevel{}).Where("cp_id in ?", cpIds).Find(&level).Error; err != nil {
model.Log.Errorf("MGetCpLevel fail:%v", err)
}
for i, v := range level {
res[v.CpId] = level[i]
}
return res
}
// 添加cp等级积分增减明细
func AddCpLevelDetail(model *domain.Model, detail CpLevelDetail) error {
return model.DB().Create(&detail).Error
}
// 获取cpRelation
func GetCpRelation(model *domain.Model, userId mysql.ID) (cpRelation CpRelation, exits bool) {
if err := model.DB().Model(CpRelation{}).Where("user_id1 = ? or user_id2 = ?", userId, userId).First(&cpRelation).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("GetCpRelation fail:%v", err)
return
}
} else {
exits = true
}
return
}
// 获取cpRelation pair
func GetCpRelationPair(model *domain.Model, userId1, userId2 mysql.ID) (cpRelation CpRelation, exits bool) {
if err := model.DB().Model(CpRelation{}).Where("user_id1 = ? AND user_id2 = ?", userId1, userId2).First(&cpRelation).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("GetCpRelation fail:%v", err)
return
} else {
// gorm.ErrRecordNotFound
if err := model.DB().Model(CpRelation{}).Where("user_id1 = ? AND user_id2 = ?", userId2, userId1).First(&cpRelation).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("GetCpRelation fail:%v", err)
return
}
} else {
exits = true
}
}
} else {
exits = true
}
return
}
// 获取cpRelation pair
func MGetCpRelation(model *domain.Model, userIds []mysql.ID) (cpRelation []CpRelation) {
if err := model.DB().Model(CpRelation{}).Where("user_id1 in ? or user_id2 in ?", userIds, userIds).Find(&cpRelation).Error; err != nil {
model.Log.Errorf("GetCpRelation fail:%v", err)
}
return
}
// 获取是否申请解绑中
func GetApplyToUnbind(model *domain.Model, userId, cpUserId mysql.ID) bool {
var total int64
if err := model.DB().Model(CpCancel{}).Where("user_id = ? AND rec_user_id = ? AND status = 1", userId, cpUserId).Count(&total).Error; err != nil {
model.Log.Errorf("GetApplyToUnbind fail:%v", err)
}
return total > 0
}
// 初始化cpLevel
func InitCpLevel(model *domain.Model, cpId, userId1, userId2 mysql.ID) error {
return model.DB().Model(CpLevel{}).Clauses(clause.OnConflict{DoNothing: true}).Create(&CpLevel{
CpId: cpId,
UserId1: userId1,
UserId2: userId2,
ExpireAt: time.Now().AddDate(0, 1, 0),
}).Error
}
// 增加cp等级积分
// 此函数并发不安全,利用mysql事件串行执行保证顺序
// 送礼1钻石=1点数
// condition
// 1.记录不存在,首充加points计算level增加90天有效期
// 2.记录存在
// 2.1 在有效期内,直接加points后判断新level,升级需要更新有效期
// 2.2 不有效期内,算首充,重置points后判断新level,升级需要更新有效期
func AddCpLevelPoints(model *domain.Model, cpRelation CpRelation, points mysql.Num, sceneType gift_e.GiftOperateSceneType) (err error) {
start := time.Now()
defer func() {
model.Log.Infof("AddCpLevelPoints cost:%v,err:%v", time.Now().Sub(start), err)
}()
var oldLevel cp_e.CpLevel
var cpLevel CpLevel
var cpLevelDetails []CpLevelDetail
if err := model.DB().Model(CpLevel{}).Where("cp_id = ?", cpRelation.Id).First(&cpLevel).Error; err != nil {
if err != gorm.ErrRecordNotFound {
return myerr.WrapErr(err)
}
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.ADD,
Num: points,
BefNum: 0,
AftNum: points,
Remark: fmt.Sprintf("send %d gift diamonds", points),
})
// 1.记录不存在,首充加points计算level增加90天有效期
var level cp_e.CpLevel
for l := cp_e.CpLevelMax; l >= cp_e.CpLevel0; l-- {
if cp_e.CpLevelPoints[l] <= points {
level = l
break
}
}
if level > 0 {
points = points - cp_e.CpLevelPoints[level] // 减去用于已用于升级的积分
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.REDUCE,
Num: cp_e.CpLevelPoints[level],
BefNum: cp_e.CpLevelPoints[level] + points,
AftNum: points,
Remark: fmt.Sprintf("Become LEVEL%d", level),
})
}
cpLevel = CpLevel{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
Points: points,
Level: level,
ExpireAt: time.Now().AddDate(0, 0, cp_e.EffectDays),
}
} else {
// 2.记录存在
// 2.1 在有效期内,直接加points后判断新level,升级需要更新有效期
if cpLevel.ExpireAt.After(time.Now()) {
cpLevel.Points += points
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.ADD,
Num: points,
BefNum: cpLevel.Points - points,
AftNum: cpLevel.Points,
Remark: fmt.Sprintf("send %d gift diamonds", points),
})
oldLevel = cpLevel.Level
levelPoint := cp_e.CpLevelPoints[oldLevel] // 已经用于升级的积分
for level := cp_e.CpLevelMax; level > oldLevel; level-- {
if cp_e.CpLevelPoints[level] <= cpLevel.Points+levelPoint {
cpLevel.Level = level
break
}
}
// 升级
if oldLevel != cpLevel.Level {
// 减去已用于升级的积分
cpLevel.Points = cpLevel.Points - (cp_e.CpLevelPoints[cpLevel.Level] - cp_e.CpLevelPoints[oldLevel])
cpLevel.ExpireAt = time.Now().AddDate(0, 0, cp_e.EffectDays)
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.REDUCE,
Num: cp_e.CpLevelPoints[cpLevel.Level] - cp_e.CpLevelPoints[oldLevel],
BefNum: cpLevel.Points + cp_e.CpLevelPoints[cpLevel.Level] - cp_e.CpLevelPoints[oldLevel],
AftNum: cpLevel.Points,
Remark: fmt.Sprintf("Become LEVEL%d", cpLevel.Level),
})
}
} else {
// 2.2 不有效期内,算首充,重置points后判断新level,更新有效期30天
oldPoints := cpLevel.Points
cpLevel.Points = points
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.ADD,
Num: points,
BefNum: oldPoints,
AftNum: cpLevel.Points,
Remark: fmt.Sprintf("send %d gift diamonds", points),
})
for level := cp_e.CpLevelMax; level >= cp_e.CpLevel0; level-- {
if cp_e.CpLevelPoints[level] <= cpLevel.Points {
cpLevel.Level = level
break
}
}
if cpLevel.Level > 0 {
cpLevel.Points -= cp_e.CpLevelPoints[cpLevel.Level] // 减去已用于升级的积分
// 明细
cpLevelDetails = append(cpLevelDetails, CpLevelDetail{
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
AddReduce: mysql.REDUCE,
Num: cp_e.CpLevelPoints[cpLevel.Level],
BefNum: cpLevel.Points + cp_e.CpLevelPoints[cpLevel.Level],
AftNum: cpLevel.Points,
Remark: fmt.Sprintf("Become SVIP%d", cpLevel.Level),
})
}
cpLevel.ExpireAt = time.Now().AddDate(0, 0, cp_e.EffectDays)
}
}
// 顺序增加明细
for _, detail := range cpLevelDetails {
if err := AddCpLevelDetail(model, detail); err != nil {
return myerr.WrapErr(err)
}
}
// 赠送cp头像头饰
if oldLevel < 3 && cpLevel.Level >= 3 {
if err := headwear_tx.SendHeadwear(model, cpRelation.UserId1, cp_e.CpHeadwearId, 30); err != nil {
return err
}
if err := headwear_tx.SendHeadwear(model, cpRelation.UserId2, cp_e.CpHeadwearId, 30); err != nil {
return err
}
}
// 群组中送礼升级
if oldLevel != cpLevel.Level && sceneType == gift_e.GroupSceneType {
go func() {
userId1, userId2 := cpRelation.UserId1, cpRelation.UserId2
model := domain.CreateModelContext(model.MyContext)
users, err := user_m.GetUserMapByIds(model, []mysql.ID{userId1, userId2})
if err != nil {
model.Log.Errorf("")
return
}
levelMsgIdMap := map[cp_e.CpLevel]uint{
cp_e.CpLevel1: 252,
cp_e.CpLevel2: 253,
cp_e.CpLevel3: 254,
cp_e.CpLevel4: 255,
cp_e.CpLevel5: 256,
}
content := fmt.Sprintf(GetTranslate(286, users[userId1].Language), GetTranslate(levelMsgIdMap[cpLevel.Level], users[userId1].Language))
if err := rpc.SendCpUpgrade(users[userId1].Nick, users[userId2].Nick, users[userId1].Avatar, users[userId2].Avatar, uint32(cpLevel.Level), content); err != nil {
model.Log.Errorf("SendCpUpgrade fail:%v", err)
}
}()
}
return cpLevel.Persistence(model)
}
// 清理过期svip积分
// 降级保级: 积分清零,svip去到大于0的等级,有效期30天
// svip0:积分清零,有效期保持过期
func ClearExpireCpPoints(model *domain.Model) error {
var cpLevels []*CpLevel
// 过期 + (积分 or level) 大于0
if err := model.DB().Table("cp_level").Joins("INNER JOIN cp_relation r ON cp_id = r.id").Where("expire_at < ? AND (points > 0 or level > 0) ", time.Now()).Find(&cpLevels).Error; err != nil {
return myerr.WrapErr(err)
}
for _, cpLevel := range cpLevels {
model.Log.Infof("ClearExpireCpPoints %v", *cpLevel)
var doubleCheck CpLevel
if err := model.DB().Model(CpLevel{}).Where("id = ?", cpLevel.ID).First(&doubleCheck).Error; err != nil {
model.Log.Errorf("double check fail:%v", err)
continue
}
if doubleCheck.ExpireAt.After(time.Now()) {
continue
}
oldPoints := cpLevel.Points
cpLevel.Level, cpLevel.Points = cp_e.CpLevel0, 0 // 清零
var newLevel cp_e.CpLevel
// 0级不刷新30天有效期
for level := cp_e.CpLevelMax; level > cp_e.CpLevel0; level-- {
if cp_e.CpLevelPoints[level] <= oldPoints {
newLevel = level
break
}
}
// 降级/保级刷新30天有效期
if newLevel > 0 {
cpLevel.Level = newLevel
cpLevel.ExpireAt = time.Now().AddDate(0, 0, cp_e.EffectDays)
// 明细
if err := AddCpLevelDetail(model, CpLevelDetail{
CpId: cpLevel.CpId,
UserId1: cpLevel.UserId1,
UserId2: cpLevel.UserId2,
AddReduce: mysql.REDUCE,
Num: cp_e.CpLevelPoints[newLevel],
BefNum: oldPoints,
AftNum: 0,
Remark: fmt.Sprintf("Become LEVEL%d", newLevel),
}); err != nil {
model.Log.Errorf("AddCpLevelDetail fail:%v", err)
}
}
if err := cpLevel.Persistence(model); err != nil {
model.Log.Errorf("cpLevel persistence fail:%v", err)
}
// 明细
if err := AddCpLevelDetail(model, CpLevelDetail{
CpId: cpLevel.CpId,
UserId1: cpLevel.UserId1,
UserId2: cpLevel.UserId2,
AddReduce: mysql.SET,
Num: oldPoints - cp_e.CpLevelPoints[newLevel],
BefNum: oldPoints - cp_e.CpLevelPoints[newLevel],
AftNum: 0,
Remark: fmt.Sprintf("Expired clear"),
}); err != nil {
model.Log.Errorf("AddCpLevelDetail fail:%v", err)
}
// 保级续送cp头像头饰
if newLevel >= 3 {
if err := headwear_tx.SendHeadwear(model, cpLevel.UserId1, cp_e.CpHeadwearId, 30); err != nil {
model.Log.Errorf("SendHeadwear fail:%v", err)
}
if err := headwear_tx.SendHeadwear(model, cpLevel.UserId2, cp_e.CpHeadwearId, 30); err != nil {
model.Log.Errorf("SendHeadwear fail:%v", err)
}
} else {
// 否则删除cp头像头饰
if err := headwear_tx.DelHeadwear(model, cpLevel.UserId1, cp_e.CpHeadwearId); err != nil {
model.Log.Errorf("DelHeadwear fail:%v", err)
}
if err := headwear_tx.DelHeadwear(model, cpLevel.UserId2, cp_e.CpHeadwearId); err != nil {
model.Log.Errorf("DelHeadwear fail:%v", err)
}
}
}
return nil
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/cp_e"
)
// svip特权
type CpPrivilege struct {
mysql.Entity
UserId mysql.ID
Type cp_e.CpPrivilege
OpenClose mysql.OpenClose
}
// 开关用于svip特权
func OpenCLoseUserSvipPrivilege(model *domain.Model, userId mysql.ID, Type cp_e.CpPrivilege, openClose mysql.OpenClose) error {
var pri CpPrivilege
if err := model.DB().Model(CpPrivilege{}).Where("user_id = ? AND `type` = ?", userId, Type).
First(&pri).Error; err != nil {
if err != gorm.ErrRecordNotFound {
return err
}
// record not found
return model.DB().Create(&CpPrivilege{
UserId: userId,
Type: Type,
OpenClose: openClose,
}).Error
}
// update
return model.DB().Model(CpPrivilege{}).Where("user_id = ? AND `type` = ?", userId, Type).
UpdateColumn("open_close", openClose).Error
}
// 批量获取用户svip特权开关
// map userId->type->open
func MGetUserSvipPrivilege(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]map[cp_e.CpPrivilege]bool, error) {
res := make(map[mysql.ID]map[cp_e.CpPrivilege]bool)
var privileges []CpPrivilege
if err := model.DB().Model(CpPrivilege{}).Where("user_id in ? AND open_close = ?", userIds, mysql.OPEN).Find(&privileges).Error; err != nil {
return res, err
}
for _, v := range privileges {
if data, ok := res[v.UserId]; ok {
data[v.Type] = true
} else {
res[v.UserId] = make(map[cp_e.CpPrivilege]bool)
res[v.UserId][v.Type] = true
}
}
return res, nil
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
)
type CpDayRank struct {
Date string
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
Score mysql.Num
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
}
// 增加cp排行榜-天
func AddCpDayRank(model *domain.Model, cpRelation CpRelation, score mysql.Num) (err error) {
date := time.Now().Format("2006-01-02")
rank := &CpDayRank{
Date: date,
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
Score: score,
}
if err = model.DB().Model(CpDayRank{}).Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "date"}, {Name: "cp_id"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"score": gorm.Expr("score + ?", rank.Score)})}).Create(rank).Error; err != nil {
model.Log.Errorf("AddCpDayRank fail:%v", err)
return err
}
return nil
}
// 分页获取cp排行榜
func PageCpDayRank(model *domain.Model, beginDate, endDate string, offset, limit int) []CpDayRank {
var ranks []CpDayRank
if err := model.DB().Table("cp_day_rank r").Joins("INNER JOIN cp_relation c ON c.id = r.cp_id").
Where("r.date BETWEEN ? AND ?", beginDate, endDate).Group("cp_id").Select("cp_id,r.user_id1,r.user_id2,SUM(r.score) score").
Order("score DESC").Offset(offset).Limit(limit).Find(&ranks).Error; err != nil {
model.Log.Errorf("PageCpDayRank fail:%v", err)
}
return ranks
}
// 获取指定cp排行榜
func GetCpDayRank(model *domain.Model, beginDate, endDate string, cpId mysql.ID) CpDayRank {
var rank CpDayRank
if err := model.DB().Table("cp_day_rank").
Where("date BETWEEN ? AND ?", beginDate, endDate).Where("cp_id = ?", cpId).Select("cp_id,user_id1,user_id2,SUM(score) score").
First(&rank).Error; err != nil {
model.Log.Errorf("GetCpDayRank fail:%v", err)
}
return rank
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"hilo-user/domain/model"
)
func (p *CpLevel) Persistence(m *domain.Model) error {
return model.Persistent(m.DB(), p)
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
)
type CpVisitor struct {
CpId mysql.ID
UserId1 mysql.ID
UserId2 mysql.ID
Visitor mysql.ID
Times mysql.Num
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
}
// 添加cp空间访问量
func AddCpSpaceVisitor(model *domain.Model, cpId, userId1, userId2, visitor mysql.ID) error {
vis := &CpVisitor{
CpId: cpId,
UserId1: userId1,
UserId2: userId2,
Visitor: visitor,
Times: 1,
}
if err := model.DB().Model(CpVisitor{}).Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "cp_id"}, {Name: "visitor"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"times": gorm.Expr("times + ?", 1)})}).Create(vis).Error; err != nil {
model.Log.Errorf("AddCpSpaceVisitor fail:%v", err)
return err
}
return nil
}
// 获取cp空间访问人数
func CountCpSpaceVisitors(model *domain.Model, cpId mysql.ID) int64 {
var cnt int64
if err := model.DB().Model(CpVisitor{}).Where("cp_id = ?", cpId).Count(&cnt).Error; err != nil {
model.Log.Errorf("CountCpSpaceVisitors fail:%v", err)
}
return cnt
}
package diamond_m
import (
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"strconv"
"time"
)
type DiamondAccount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondNum mysql.Num
PinkDiamondNum mysql.Num
Status diamond_e.StatusAccount
}
//账号详情
type DiamondAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
// 粉钻详情
type DiamondPinkAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
//账号操作配置
type DiamondOperateSet struct {
mysql.Entity
*domain.Model `gorm:"-"`
DiamondNum mysql.NumAll
FrequencyNum mysql.NumAll
FrequencyDay mysql.NumAll
DiamondMaxNum mysql.NumAll
AddReduce mysql.AddReduce
Type diamond_e.OperateType
Name mysql.Str
Status mysql.UserYesNo
DiamondType diamond_e.OperateType
}
//通过userId获取帐号
func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAccount, error) {
var diamondAccount DiamondAccount
if err := model.Db.WithContext(model).Where(&DiamondAccount{
UserId: userId,
}).First(&diamondAccount).Error; err != nil {
return nil, myerr.WrapErr(err)
}
diamondAccount.Model = model
return &diamondAccount, nil
}
//匹配条件扣费
func (diamondAccount *DiamondAccount) ChangeDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(operateType, originId, diamondNum)
}
//钻石操作记录,
func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
var diamondOperateSet DiamondOperateSet
var err error
if err = diamondAccount.Db.Where(&DiamondOperateSet{
Type: operateType,
Status: mysql.USER,
DiamondType: mysql.DiamondYellow,
}).First(&diamondOperateSet).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//判断是增加,账号是否被冻结
if diamondAccount.Status == diamond_e.Frozen && diamondOperateSet.AddReduce == mysql.REDUCE {
return nil, bizerr.DiamondAccountFrozen
}
//无限,检查次数
var count int64
if diamondOperateSet.FrequencyDay == -1 {
if diamondOperateSet.FrequencyNum != -1 {
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
//return nil, myerr.NewSysError("钻石操作次数多大, userId:" + mysql.IdToStr(diamondAccount.UserId) + " diamondOperateSetId" + mysql.IdToStr(diamondOperateSet.ID))
}
}
} else if diamondOperateSet.FrequencyDay == 1 {
beginTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
if err != nil {
return nil, myerr.WrapErr(err)
}
//一天的次数
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Where("created_time >= ? ", beginTime).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
}
//终极拦截,利用
diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1) as n from diamond_account_detail d where d.user_id = " + strconv.FormatUint(diamondAccount.UserId, 10) + " and d.operate_type = " + strconv.FormatUint(uint64(operateType), 10) + " and d.created_time >= from_unixtime(" + strconv.FormatInt(utils.GetZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )")
}
//-1,代表值无效,由参数给与
var upateDiamondNum mysql.Num
if diamondOperateSet.DiamondNum == -1 {
upateDiamondNum = diamondNum
} else {
upateDiamondNum = mysql.Num(diamondOperateSet.DiamondNum)
}
var afterNum mysql.Num
if diamondOperateSet.AddReduce == mysql.ADD {
afterNum = diamondAccount.DiamondNum + upateDiamondNum
} else if diamondOperateSet.AddReduce == mysql.REDUCE {
if diamondAccount.DiamondNum < upateDiamondNum {
return nil, bizerr.DiamondNoEnough
}
afterNum = diamondAccount.DiamondNum - upateDiamondNum
} else {
return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(mysql.Type(diamondOperateSet.AddReduce)))
}
diamondAccountDetail := &DiamondAccountDetail{
Model: diamondAccount.Model,
UserId: diamondAccount.UserId,
DiamondAccountId: diamondAccount.ID,
OperateId: diamondOperateSet.ID,
OperateType: diamondOperateSet.Type,
OriginId: originId,
AddReduce: diamondOperateSet.AddReduce,
Num: upateDiamondNum,
Remark: diamondOperateSet.Name,
BefNum: diamondAccount.DiamondNum,
AftNum: afterNum,
diamondAccount: diamondAccount,
}
return diamondAccountDetail, err
}
// 此方法必须要在事务里面调用
func ChangeDiamondAccountDetail(model *domain.Model, operateType diamond_e.OperateType, originId mysql.ID, userId mysql.ID, diamondNum mysql.Num) error {
diamondAccount, err := GetDiamondAccountByUserId(model, userId)
if err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(operateType, originId, diamondNum)
if err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
if err := diamondAccountDetail.PersistentNoInTransactional(); err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
return nil
}
package diamond_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/domain/model"
"hilo-user/myerr"
"strconv"
)
func (diamondAccountDetail *DiamondAccountDetail) PersistentNoInTransactional() error {
//fixme: 这里有点奇怪, diamondAccount持久化动作在diamondAccountDetail持久化之后,RowsAffected 就一定是0
txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
}
if diamondAccountDetail.AddReduce == mysql.ADD {
//增加
txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num))
} else if diamondAccountDetail.AddReduce == mysql.REDUCE {
//减少,保证不能扣成负数
txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num))
} else {
myerr.NewSysError("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce)))
}
if err := txDiamondAccount.Error; err != nil {
return myerr.WrapErr(err)
}
if txDiamondAccount.RowsAffected == 0 {
diamondAccountDetail.Log.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
return myerr.NewWaring("gorm condition update.RowsAffected = 0")
}
//持久化diamondAccountDetail
if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
return myerr.WrapErr(err)
}
//改变diamondAccount值
if diamondAccountDetail.diamondAccount == nil {
return myerr.NewSysError("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID)))
}
var newDiamondAccount DiamondAccount
if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil {
return myerr.WrapErr(err)
}
if newDiamondAccount.DiamondNum < 0 {
return myerr.NewSysError("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID)))
}
return nil
}
package event_m
import "hilo-user/domain/model"
func (p *EventGiftSendOffsetHiloUser) Persistence() error {
return model.Persistent(p.Db, p)
}
func (p *EventGiftSend) Persistence() error {
return model.Persistent(p.Db, p)
}
package event_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/pkg/errors"
"gorm.io/gorm"
"time"
)
// 送礼事件消息
type EventGiftSend struct {
mysql.Entity
*domain.Model `gorm:"-"`
Proto mysql.Type
Payload []byte
Mark mysql.YesNo
MarkHiloGroup mysql.YesNo
MarkHiloUser mysql.YesNo
}
func (EventGiftSend) TableName() string {
return "event_gift_send"
}
// 偏移值
type EventGiftSendOffsetHiloUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
MarkOffset mysql.ID
}
// 获取当前偏移值
func Offset(model *domain.Model) (*EventGiftSendOffsetHiloUser, error) {
offset := new(EventGiftSendOffsetHiloUser)
if err := model.Db.WithContext(model).First(offset).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("Offset fail:%v", err)
return nil, err
}
// gorm.ErrRecordNotFound
}
offset.Model = model
return offset, nil
}
// 批量获取送礼
func FetchEventGiftSend(model *domain.Model, limit int) ([]*EventGiftSend, *EventGiftSendOffsetHiloUser, error) {
offset, err := Offset(model)
if err != nil {
return nil, nil, err
}
var events []*EventGiftSend
if err := model.Db.WithContext(model).Model(EventGiftSend{}).
Where("id > ?", offset.MarkOffset).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchEventGiftSend fail:%v", err)
return nil, nil, err
}
return events, offset, nil
}
// 标记已完成
func (p *EventGiftSend) MarkDone() error {
p.MarkHiloUser = mysql.YES
result := p.Db.WithContext(p.Model).Model(EventGiftSend{}).Where("id = ?", p.ID).Update("mark_hilo_user", p.MarkHiloUser).Limit(1)
if result.Error != nil {
return result.Error
}
if result.RowsAffected <= 0 {
p.Model.Log.Errorf("MarkDone row affeced 0")
return errors.New("row affect 0")
}
return nil
}
// 查询过去1小时-5分钟前未mark的事件
// 用来补偿
// 记得加limit
func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGiftSend, error) {
offset, err := Offset(model)
if err != nil {
return nil, err
}
t := time.Now().Add(-time.Minute * 5)
lt := t.Add(-time.Hour)
var events []*EventGiftSend
if err := model.Db.WithContext(model).Model(EventGiftSend{}).
Where("mark_hilo_user = ?", mysql.NO).
Where("id <= ?", offset.MarkOffset).
Where("created_time < ?", t).
Where("created_time > ?", lt).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchUnMarkEvents fail:%v", err)
return nil, err
}
return events, nil
}
// 补偿加上unmark的event
func AddUnMarkEvent(model *domain.Model, event *EventGiftSend) error {
return model.Db.WithContext(model).Create(event).Error
}
......@@ -191,7 +191,7 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) {
if err == nil {
return r.Lang, nil
} else if err == gorm.ErrRecordNotFound {
return res_e.DEFAULT_LANG, nil
return res_e.DefaultLang, nil
} else {
return "", myerr.WrapErr(err)
}
......
......@@ -123,3 +123,15 @@ func CheckHeadwearValidById(model *domain.Model, id mysql.ID) (bool, error) {
return true, nil
}
}
func GetResHeadwearMap(db *gorm.DB) (map[uint64]ResHeadwear, error) {
rows := make([]ResHeadwear, 0)
if err := db.Model(&ResHeadwear{}).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]ResHeadwear, 0)
for _, i := range rows {
result[i.ID] = i
}
return result, nil
}
\ No newline at end of file
......@@ -2,8 +2,10 @@ package res_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"gorm.io/gorm"
"hilo-user/_const/enum/res_e"
"time"
)
type ResMedal struct {
......@@ -41,3 +43,39 @@ func GetUserMedalLevelMap(db *gorm.DB) (map[uint64]uint8, map[uint8][]uint64, er
}
return medalTypes, result, nil
}
var medalCache = gcache.New(1000).LRU().Build()
var medalMapCache = gcache.New(1).LRU().Build()
const medalKey = "MEDAL"
// pprof看到内存分配很多
// 加上15min lru
func MedalGetAll(db *gorm.DB) ([]ResMedal, error) {
if data, err := medalCache.Get(medalKey); err == nil {
return data.([]ResMedal), nil
}
rows := make([]ResMedal, 0)
err := db.Find(&rows).Error
if err != nil {
return nil, err
}
_ = medalCache.SetWithExpire(medalKey, rows, time.Minute*15)
return rows, nil
}
func MedalGetAllMap(db *gorm.DB) (map[uint32]ResMedal, error) {
if data, err := medalMapCache.Get(medalKey); err == nil {
return data.(map[uint32]ResMedal), nil
}
rows, err := MedalGetAll(db)
if err != nil {
return nil, err
}
result := make(map[uint32]ResMedal, 0)
for _, i := range rows {
result[uint32(i.ID)] = i
}
_ = medalMapCache.SetWithExpire(medalKey, result, time.Minute*15)
return result, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/res_e"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
)
type ResProperty struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
}
type ResPropertyDiamond struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResPropertyId mysql.ID
DiamondNum mysql.Num
Second mysql.Num
Status mysql.UserYesNo
}
type ResPropertyAvatar struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResPropertyId mysql.ID
Type res_e.ResPropertyAvatarType
SendUserId mysql.ID
ReceiverUserId mysql.ID
}
func InitResPropertyDiamond(model *domain.Model, resPropertyId mysql.ID, diamondNum mysql.Num, second mysql.Num) *ResPropertyDiamond {
return &ResPropertyDiamond{
Model: model,
ResPropertyId: resPropertyId,
DiamondNum: diamondNum,
Second: second,
Status: mysql.NOUSER,
}
}
//id获取头饰,不存在则抛异常
func GetPropertyById(model *domain.Model, id mysql.ID) (*ResProperty, error) {
resProperty := ResProperty{}
if err := model.Db.Model(&ResProperty{}).First(&resProperty, id).Error; err != nil {
return nil, myerr.WrapErr(err)
} else {
resProperty.Model = model
return &resProperty, nil
}
}
func GetResPropertyDiamond(model *domain.Model, resPropertyDiamondId mysql.ID) (*ResPropertyDiamond, error) {
resPropertyDiamond := ResPropertyDiamond{}
if err := model.Db.Model(&ResPropertyDiamond{}).First(&resPropertyDiamond, resPropertyDiamondId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if resPropertyDiamond.Status == mysql.NOUSER {
return nil, bizerr.ResPropertyDiamondNoUse
}
return &resPropertyDiamond, nil
}
func GetResPropertyDiamondByPropertyIdOrNil(model *domain.Model, resPropertyId mysql.ID) (*ResPropertyDiamond, error) {
resPropertyDiamond := ResPropertyDiamond{}
if err := model.Db.Model(&ResPropertyDiamond{}).Where(&ResPropertyDiamond{
ResPropertyId: resPropertyId,
}).First(&resPropertyDiamond).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resPropertyDiamond.Model = model
return &resPropertyDiamond, nil
}
//设置成未使用
func (resPropertyDiamond *ResPropertyDiamond) SetUser() *ResPropertyDiamond {
resPropertyDiamond.Status = mysql.USER
return resPropertyDiamond
}
//设置成未使用
func (resPropertyDiamond *ResPropertyDiamond) SetNoUser() *ResPropertyDiamond {
resPropertyDiamond.Status = mysql.NOUSER
return resPropertyDiamond
}
func (resPropertyDiamond *ResPropertyDiamond) SetDiamondNum(diamondNum uint32) *ResPropertyDiamond {
resPropertyDiamond.DiamondNum = diamondNum
return resPropertyDiamond
}
func (resPropertyDiamond *ResPropertyDiamond) SetSecond(second uint32) *ResPropertyDiamond {
resPropertyDiamond.Second = second
return resPropertyDiamond
}
func AddProperty(model *domain.Model, p *ResProperty) error {
return model.Db.Create(p).Error
}
func EditProperty(model *domain.Model, propertyId uint64, name, picUrl, effectUrl string) error {
activityConfig := ResProperty{Entity: mysql.Entity{ID: propertyId}}
err := model.Db.First(&activityConfig).Error
if err != nil {
return err
}
activityConfig.Name = name
activityConfig.PicUrl = picUrl
activityConfig.EffectUrl = effectUrl
return model.Db.Save(&activityConfig).Error
}
func (p *ResProperty) Get(db *gorm.DB) error {
return db.Where(p).First(p).Error
}
func (p *ResProperty) GetAll(db *gorm.DB) (map[uint64]ResProperty, error) {
rows := make([]ResProperty, 0)
if err := db.Where(p).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]ResProperty, 0)
for _, i := range rows {
result[i.ID] = i
}
return result, nil
}
func (p *ResPropertyAvatar) GetAll(db *gorm.DB) (map[uint64]ResPropertyAvatar, error) {
rows := make([]ResPropertyAvatar, 0)
if err := db.Where(p).Find(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
result := make(map[uint64]ResPropertyAvatar, 0)
for _, i := range rows {
result[i.ResPropertyId] = i
}
return result, nil
}
......@@ -27,7 +27,7 @@ func GetResMultiTextBy(db *gorm.DB, msgId uint, Language mysql.Str) (*ResMultiTe
if err == gorm.ErrRecordNotFound {
if err := db.Where(&ResMultiText{
MsgId: msgId,
Language: res_e.DEFAULT_LANG,
Language: res_e.DefaultLang,
}).First(&r).Error; err != nil {
return nil, myerr.WrapErr(err)
}
......
......@@ -89,3 +89,15 @@ func GetUserMedal(db *gorm.DB, userId mysql.ID) ([]uint32, error) {
}
return result, nil
}
func BatchGetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userIds []mysql.ID) (map[uint64][]uint32, error) {
result := make(map[uint64][]uint32, 0)
for _, u := range userIds {
a, err := GetUserMedalMerge(logger, db, u)
if err != nil {
return nil, err
}
result[u] = a
}
return result, nil
}
......@@ -108,4 +108,32 @@ type UserPropertyLog struct {
Type property_e.UserPropertyLogType
AddSecond *mysql.Num
UpdateEndTime *time.Time
}
\ No newline at end of file
}
func (userProperty *UserProperty) BatchGet(db *gorm.DB, userIds []uint64) (map[uint64]uint64, error) {
rows := make([]UserProperty, 0)
if err := db.Model(userProperty).
Where("end_time > NOW() AND user_id IN ?", userIds).Order("id DESC").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]uint64, 0)
tmp := make(map[uint64]uint64, 0)
for _, i := range rows {
if _, ok := result[i.UserId]; !ok {
if i.Using == property_e.YesUsing {
// using = true且id最大,就确定是当前使用的
result[i.UserId] = i.PropertyId
} else if _, ok := tmp[i.UserId]; !ok {
// using = false且id最大,先记下,因为不知道还有没有using=true的
tmp[i.UserId] = i.PropertyId
}
}
}
for k, v := range tmp {
// result中没有的,就采用tmp保存的
if _, ok := result[k]; !ok {
result[k] = v
}
}
return result, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
"strings"
)
type SuperManager struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
IsAll bool
Countries string
}
func IsSuperManager(model *domain.Model, userId mysql.ID) (bool, error) {
var n int64
if err := model.Db.Model(&SuperManager{}).Where(&SuperManager{
UserId: userId,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
return n > 0, nil
}
// 对某人是否有超管权限
func IsSuperManagerV2(model *domain.Model, userId, targetUserId mysql.ID) (bool, error) {
var man SuperManager
if err := model.Db.Model(&SuperManager{}).Where(&SuperManager{
UserId: userId,
}).First(&man).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("IsSuperManagerV2 fail:%v", err)
}
return false, nil
}
if man.IsAll {
return true, nil
}
targetUser, err := GetUser(model, targetUserId)
if err != nil {
return false, err
}
countries := strings.Split(man.Countries, ",")
for _, c := range countries {
if c == targetUser.Country {
return true, nil
}
}
return false, nil
}
func GetSuperManagerAll(model *domain.Model) ([]uint64, error) {
var superManagers []SuperManager
if err := model.Db.Model(&SuperManager{}).Find(&superManagers).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userIds := make([]uint64, 0, len(superManagers))
for i, _ := range superManagers {
userIds = append(userIds, superManagers[i].UserId)
}
return userIds, nil
}
/*
func GetSuperManagerMap(model *domain.Model) (map[uint64]struct{}, error) {
userIds, err := GetSuperManagerAll(model)
if err != nil {
return nil, err
}
userIdMap := map[uint64]struct{}{}
for i, _ := range userIds {
userIdMap[userIds[i]] = struct{}{}
}
return userIdMap, nil
}*/
......@@ -6,6 +6,7 @@ import (
"hilo-user/_const/enum/user_e"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"time"
)
//用户信息
......@@ -106,3 +107,40 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) {
user.Model = model
return &user, nil
}
func ToUserTiny(user *User) *UserTiny {
return &UserTiny{
ID: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
Description: user.Description,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode(),
IsLogout: IfLogout(user.LogoutTime),
Birthday: BirthdayToUint64(&user.Birthday),
}
}
func IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 {
if *birthday == 0 {
return nil
}
return (*uint64)(birthday)
}
//获取用户
func GetUsers(model *domain.Model, ids []mysql.ID) ([]*User, error) {
res := make([]*User, 0)
if err := model.Db.WithContext(model.Context).Where("id in (?)", ids).Find(&res).Error; err != nil {
return nil, myerr.WrapErr(err)
}
return res, nil
}
......@@ -43,3 +43,24 @@ func GetVip(db *gorm.DB, userId uint64) (*UserVip, error) {
}
return nil, nil
}
func BatchGetVips(userIds []uint64) (map[uint64]*int64, error) {
rows := make([]UserVip, 0)
err := mysql.Db.Where("user_id IN ?", userIds).Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[uint64]*int64, 0)
for _, i := range userIds {
result[i] = nil
}
now := time.Now()
for _, i := range rows {
if i.ExpireAt.After(now) {
ts := i.ExpireAt.Unix()
result[i.UserId] = &ts
}
}
return result, nil
}
package cp_s
import (
"encoding/json"
"git.hilo.cn/hilo-common/_const/common"
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/myerr/comerr"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/txop/msg"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/diamond_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
)
func InviteCpRelation(myCtx *mycontext.MyContext, myUserId uint64, externalId, lang string) error {
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return err
}
userInvite, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return err
}
if userInvite.ID == myUserId {
return bizerr.InvalidParameter
}
// 自己是否有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return err
}
if myCp.Id > 0 {
return myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_HAS_CP, lang, comerr.AlreadyHasCp))
}
// 对方是否已经有cp了
inviCp, err := cp_m.GetCp(model, userInvite.ID)
if err != nil {
return err
}
if inviCp.Id > 0 {
return myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_HAS_CP, lang, comerr.AlreadyHasCp))
}
// 我是否发起过cp邀请,且还未被处理
myInvite, err := cp_m.GetCpInvite(model, user.ID, 0, cp_e.CpInvite)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
if myInvite != nil && myInvite.Id > 0 {
return bizerr.CpAlreadyInvite
}
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_WANT_BE_YOUR_CP, lang)
if err != nil {
return err
}
tip, err := msg.GetResMultiTextBy(model, common.MSG_ID_EXPIRES_AFTER_24_H, lang)
if err != nil {
return err
}
err = model.Transaction(func(model *domain.Model) error {
// 创建邀请记录
cpInvId, err := cp_m.CreateCpInvite(model, myUserId, userInvite.ID, cp_e.CpRelationInviteDiamond)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 扣费
err = diamond_m.ChangeDiamondAccountDetail(model, diamond_e.CpInvite, cpInvId, myUserId, cp_e.CpRelationInviteDiamond)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 发送私信-邀请
data, _ := json.Marshal(cp_m.CpInviteMessage{
Identifier: "CpInviteMessage",
Msg: content,
Tip: tip,
Sender: user_m.ToUserTiny(user),
MsgType: 1,
MsgId: cpInvId,
})
if err := tencentyun.BatchSendCustomMsg(model, 1, user.ExternalId, []string{userInvite.ExternalId}, string(data), "cp邀请"); err != nil {
model.Log.Errorf("BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// socket 推送弹窗
go rpc.SendCpInviteNotice(userInvite.ID, user.Code, user.Nick, user.Avatar, content, user.ExternalId)
return nil
}
func CancelCpRelation(myCtx *mycontext.MyContext, myUserId uint64, externalId, lang string) error {
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return err
}
userRec, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return err
}
if userRec.ID == myUserId {
return bizerr.InvalidParameter
}
tip, err := msg.GetResMultiTextBy(model, common.MSG_ID_EXPIRES_AFTER_24_H, lang)
if err != nil {
return err
}
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_WANT_UNBIND_CP, lang)
if err != nil {
return err
}
// 自己没有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return err
}
if myCp.Id == 0 {
return myerr.WrapErr(bizerr.InvalidParameter)
}
// 对方没有cp了
inviCp, err := cp_m.GetCp(model, userRec.ID)
if err != nil {
return err
}
if inviCp.Id == 0 {
return myerr.WrapErr(bizerr.InvalidParameter)
}
// 是否有关于我的cp解除申请,且还未被处理
myCancel, err := cp_m.GetCpCancelWithMe(model, user.ID, cp_e.CpCancel)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
if myCancel != nil && myCancel.Id > 0 {
return bizerr.CpHaveCancelNoDeal
}
err = model.Transaction(func(model *domain.Model) error {
// 创建邀请记录
cancelId, err := cp_m.CreateCpCancel(model, myUserId, userRec.ID)
if err != nil {
model.Log.Errorf("CancelCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 发送私信-发起解除
data, _ := json.Marshal(cp_m.CpCancelMessage{
Identifier: "CpCancelMessage",
Msg: content,
Tip: tip,
Sender: user_m.ToUserTiny(user),
MsgType: 2,
MsgId: cancelId,
})
if err := tencentyun.BatchSendCustomMsg(model, 1, user.ExternalId, []string{userRec.ExternalId}, string(data), "cp解除"); err != nil {
model.Log.Errorf("CancelCpRelation BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CancelCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
return nil
}
package event_s
import (
"git.hilo.cn/hilo-common/domain"
"github.com/jinzhu/now"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/event/gift_ev"
"hilo-user/domain/model/cp_m"
"time"
)
// 送礼增加cp等级
// 送礼增加cp排行榜
func CpGiftEvent() {
gift_ev.AddSendGiftEventSync(func(model *domain.Model, event interface{}) error {
sendGiftEvent, ok := event.(*gift_ev.SendGiftEvent)
if !ok {
model.Log.Errorf("AddSendGiftEventAsync event type err")
return nil
}
// 只处理cp礼物
if !sendGiftEvent.ResGift.Cp {
return nil
}
for _, receiverUid := range sendGiftEvent.ReceiveUserIds {
diamonds := sendGiftEvent.GiftN * sendGiftEvent.ResGift.DiamondNum
// 有cp关系
if cpRelation, exits := cp_m.GetCpRelationPair(model, sendGiftEvent.SendUserId, receiverUid); exits {
if err := cp_m.AddCpLevelPoints(model, cpRelation, diamonds, sendGiftEvent.SceneType); err != nil {
model.Log.Errorf("AddCpLevelPoints fail:%v", err)
}
if err := cp_m.AddCpDayRank(model, cpRelation, diamonds); err != nil {
model.Log.Errorf("AddCpDayRank fail:%v", err)
}
// 检查最新的等级
if cpLevel := cp_m.GetCpLevel(model, cpRelation.Id); cpLevel.CpId >= 0 {
points := cpLevel.Points + cp_e.CpLevelPoints[cpLevel.Level]
if err := cp_m.UpdateCpAchievement(model, cpLevel.CpId, cpRelation.UserId1, cpRelation.UserId2, cp_e.CpAchievementLevel, points); err != nil {
model.Log.Errorf("UpdateCpAchievement fail:%v", err)
}
}
// 检查最高的分数
for _, queryType := range []string{"day", "week", "month"} {
var beginDate, endDate string
var cpAchievementType cp_e.CpAchievement
switch queryType {
case "day":
beginDate, endDate = time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02")
cpAchievementType = cp_e.CpAchievementDayRank
case "week":
beginDate = now.BeginningOfWeek().Format("2006-01-02")
endDate = now.EndOfWeek().Format("2006-01-02")
cpAchievementType = cp_e.CpAchievementWeekRank
case "month":
beginDate = now.BeginningOfMonth().Format("2006-01-02")
endDate = now.EndOfMonth().Format("2006-01-02")
cpAchievementType = cp_e.CpAchievementMonthRank
}
if data := cp_m.GetCpDayRank(model, beginDate, endDate, cpRelation.Id); data.Score > 0 {
if err := cp_m.UpdateCpAchievement(model, cpRelation.Id, cpRelation.UserId1, cpRelation.UserId2, cpAchievementType, data.Score); err != nil {
model.Log.Errorf("UpdateCpAchievement fail:%v", err)
}
}
}
// 检查最新日周月榜单
return nil // 业务场景允许提前break(cp是唯一的)
}
}
return nil
})
}
package event_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/event/cp_ev"
"hilo-user/domain/model/cp_m"
"hilo-user/myerr/bizerr"
)
// cp空间访问
func CpSpaceVisitEvent() {
cp_ev.AddCpSpaceVisitAsync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*cp_ev.SpaceVisitEvent)
if !ok {
return bizerr.InvalidParameter
}
if err := cp_m.AddCpSpaceVisitor(model, e.CpId, e.UserId1, e.UserId2, e.UserId); err != nil {
model.Log.Errorf("AddCpSpaceVisitor fail:%v", err)
}
if cnt := cp_m.CountCpSpaceVisitors(model, e.CpId); cnt > 0 {
if err := cp_m.UpdateCpAchievement(model, e.CpId, e.UserId1, e.UserId2, cp_e.CpAchievementVisitors, mysql.Num(cnt)); err != nil {
model.Log.Errorf("UpdateCpAchievement fail:%v", err)
}
}
return nil
})
}
......@@ -14,6 +14,8 @@ import (
func EventInit() {
UserBagSendEvent()
CpGiftEvent()
CpSpaceVisitEvent()
}
func UserBagSendEvent() {
......
package event_s
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/domain/event/gift_ev"
"hilo-user/domain/model/event_m"
"runtime/debug"
)
// 每次处理500条
const BatchCount = 500
type GiftSendEventService struct {
svc *domain.Service
}
func NewGiftSendEventService(myContext *mycontext.MyContext) *GiftSendEventService {
svc := domain.CreateService(myContext)
return &GiftSendEventService{svc}
}
//
func (s *GiftSendEventService) Consume() error {
defer func() {
if err := recover(); err != nil {
s.svc.Log.Errorf("ExceptionHandle GiftSendEventService Consume SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
}
}()
var model = domain.CreateModel(s.svc.CtxAndDb)
return model.Transaction(func(model *domain.Model) error {
events, offset, err := event_m.FetchEventGiftSend(model, BatchCount)
if err != nil {
return err
}
for k := range events {
cpEvent := &event_m.EventGiftSend{
Entity: mysql.Entity{
ID: events[k].ID,
CreatedTime: events[k].CreatedTime,
UpdatedTime: events[k].UpdatedTime,
},
Proto: events[k].Proto,
Payload: events[k].Payload,
MarkHiloUser: events[k].MarkHiloUser,
}
if cpEvent.MarkHiloUser == mysql.YES {
model.Log.Warnf("already consume msg :%v", cpEvent)
continue
}
sendGiftEvent := new(gift_ev.SendGiftEvent)
if err := json.Unmarshal(cpEvent.Payload, sendGiftEvent); err != nil {
model.Log.Errorf("json msg fail,event:%v,err:%v", cpEvent, err)
continue
}
// 标记已经处理,mark比publish事件提前,尽量避免异步事件重复执行
cpEvent.Model = model
err = cpEvent.MarkDone()
if err != nil {
model.Log.Errorf("consume msg fail,event:%v,err:%v", cpEvent, err)
return err
}
if err := gift_ev.PublishSendGiftEvent(model, sendGiftEvent); err != nil {
model.Log.Errorf("PublishSendGiftEvent fail,event:%v,err:%v", string(cpEvent.Payload), err)
return err
}
}
// 最后一次提交offset
if len(events) > 0 {
offset.MarkOffset = events[len(events)-1].ID
return offset.Persistence()
}
return nil
})
}
......@@ -19,6 +19,16 @@ require (
gorm.io/gorm v1.23.8
)
require (
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/robfig/cron v1.2.0
)
require (
github.com/bluele/gcache v0.0.2
github.com/jinzhu/now v1.1.5
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
......@@ -37,7 +47,8 @@ require (
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/hashicorp/consul/api v1.7.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect
......@@ -47,11 +58,10 @@ require (
github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/serf v0.9.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/joho/godotenv v1.3.0 // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
......@@ -63,11 +73,16 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.479 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ims v1.0.479 // indirect
github.com/tencentyun/tls-sig-api-v2-golang v1.0.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 // indirect
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
......
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=
github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src v0.0.0-20200910100525-12b7f1b63a6a/go.mod h1:4bXIK0ntDk9CqAXobmomWd7dedbfNv/aaIpmpqqzt+A=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
......@@ -10,15 +13,53 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274 h1:u48e7I7h/BY5uDP8xiIFNaUkdTVk7hjj/Sucg8FrxNU=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2 v1.16.12/go.mod h1:C+Ym0ag2LIghJbXhfXZ0YEEp49rBWowxKzJLUoob0ts=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM=
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.19/go.mod h1:llxE6bwUZhuCas0K7qGiu5OgMis3N7kdWtFSxoHmJ7E=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.13/go.mod h1:lB12mkZqCSo5PsdBFLNqc2M/OOYgNAy8UtaktyuWvE8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.0/go.mod h1:Nf3QiqrNy2sj3Rku+9z4nN/bThI97gQmR7YxG3s+ez8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc=
github.com/aws/aws-sdk-go-v2/service/rekognition v1.20.1/go.mod h1:JziF+gVo2UhFc4A52j/0Zcjpba2oxoMp/TyJ+0tZkIg=
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.5/go.mod h1:qFKU5d+PAv+23bi9ZhtWeA+TmLUz7B/R59ZGXQ1Mmu4=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
github.com/aws/smithy-go v1.13.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
......@@ -26,10 +67,19 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
......@@ -70,18 +120,41 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.7.0 h1:tGs8Oep67r8CcA2Ycmb/8BLBcJ70St44mF2X10a/qPg=
github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg=
github.com/hashicorp/consul/sdk v0.6.0 h1:FfhMEkwvQl57CildXJyGHnwGGM4HMODGyfjGwNM1Vdw=
......@@ -117,6 +190,8 @@ github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.3 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM=
github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
......@@ -139,12 +214,14 @@ github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGn
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
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/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
......@@ -186,9 +263,20 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
......@@ -198,8 +286,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
......@@ -211,11 +305,13 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
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/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
......@@ -224,8 +320,16 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.479 h1:3kwDb6p1J3LxmwnNgSSEheemPffo+vMewoDzKysYdig=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.479/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ims v1.0.479 h1:xDmo1rBmSJ7Hw3iOa6DQ/++z1d7pgsEVKrZno35zR7w=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ims v1.0.479/go.mod h1:3YlJ1g/Ko/iFgyBJdok+dRPTH6zRB6BBopAcFkbujPc=
github.com/tencentyun/tls-sig-api-v2-golang v1.0.0 h1:NavMw9XO2iCLv8hTKaJW2kTaGR2SdNljMABbe39yu6Q=
github.com/tencentyun/tls-sig-api-v2-golang v1.0.0/go.mod h1:u7WiArmCTXTaQAHJwAOaLgpJ5e2xdY5/cgMEy3ubL60=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
......@@ -233,14 +337,29 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
......@@ -249,11 +368,21 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
......@@ -261,48 +390,96 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 h1:xFbv3LvlvQAmbNJFCBKRv1Ccvnh9FVsW0FX2kTWWowE=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
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=
......@@ -312,3 +489,5 @@ gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
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=
......@@ -3,6 +3,7 @@ package main
import (
"fmt"
"git.hilo.cn/hilo-common/resource/consul"
"hilo-user/cron"
"hilo-user/domain/service/event_s"
"hilo-user/route"
)
......@@ -14,7 +15,7 @@ const (
)
func main() {
//cron.Init() // 开启定时任务
cron.Init() // 开启定时任务
event_s.EventInit() // 注册事件(内部事件+mysql拟kafka)
r := route.InitRouter() // 注册路由
consul.RegisterToConsul(PORT, RegisterName, RegisterTag) // 服务注册
......
......@@ -20,30 +20,12 @@ var (
DiamondFrequency = myerr.NewBusinessCode(4001, "Diamond operation frequency too high", myerr.BusinessData{})
DiamondAccountFrozen = myerr.NewBusinessCode(4004, "Diamond Account Frozen", myerr.BusinessData{})
// 游戏
GameInvalidParameter = myerr.NewGameError(10002, "invalid parameter")
GameTokenInvalid = myerr.NewGameError(1004, "user token invalid")
GameTokenExpire = myerr.NewGameError(1005, "user token expire")
ResPropertyDiamondNoUse = myerr.NewBusinessCode(5004, "Property can not buy", myerr.BusinessData{}) //头饰不能买
CpNotRelation = myerr.NewBusinessCode(6000, "cp not relation", myerr.BusinessData{})
// 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
// 游戏服务的错误码,6位,50XXX
GameAddNoPermissions = myerr.NewBusinessCode(50100, "Only room administrators can create users", myerr.BusinessData{}) // 权限不足
GameAddNotOnMic = myerr.NewBusinessCode(50101, "Need on mic", myerr.BusinessData{}) // 需要在麦上才能创建、加入游戏
GameHaveNoEnd = myerr.NewBusinessCode(50102, "Group user have no end", myerr.BusinessData{}) // 房间还有未结束的游戏
GameNotFound = myerr.NewBusinessCode(50103, "Game not found", myerr.BusinessData{}) //
GameStart = myerr.NewBusinessCode(50104, "Gaming", myerr.BusinessData{}) //
GameAlreadyJoin = myerr.NewBusinessCode(50105, "Already Joined", myerr.BusinessData{}) // 已经加入了游戏
GameNotJoin = myerr.NewBusinessCode(50106, "Not Join user", myerr.BusinessData{}) // 还未加入游戏
GameCannotClose = myerr.NewBusinessCode(50107, "Have no power to close user", myerr.BusinessData{}) // 没有权限关闭游戏
GameCloseGaming = myerr.NewBusinessCode(50108, "Can't close a user in progress", myerr.BusinessData{}) // 不能关闭进行中的游戏
GamePlayerNumWrong = myerr.NewBusinessCode(50109, "Game player num wrong", myerr.BusinessData{}) // 玩家数量错误
GameHaveNoMyRoom = myerr.NewBusinessCode(50110, "Have no my room", myerr.BusinessData{}) // 自己没有房间
GameHaveNoEndGame = myerr.NewBusinessCode(50111, "The last user is not over yet, cannot create/join a user", myerr.BusinessData{}) // 已经加入了其他房间的游戏
GameExitWrong = myerr.NewBusinessCode(50112, "Can not exit user", myerr.BusinessData{}) // 离开游戏失败
GameDiamondCannotEdit = myerr.NewBusinessCode(50113, "Game diamond can not edit", myerr.BusinessData{}) //
GameSettleWrong = myerr.NewBusinessCode(50114, "Game settle wrong", myerr.BusinessData{}) // 结算修改错误
GameCloseWrong = myerr.NewBusinessCode(50115, "Game close wrong", myerr.BusinessData{}) // 关闭错误
GameJoinFailed = myerr.NewBusinessCode(50116, "Join failed", myerr.BusinessData{}) // 加入失败
CpAlreadyInvite = myerr.NewBusinessCode(50120, "Already invited", myerr.BusinessData{}) // 已经发送过邀请了
CpHaveCancelNoDeal = myerr.NewBusinessCode(50121, "You have a cancel apply", myerr.BusinessData{}) // 有接触申请需要处理
)
......@@ -2,6 +2,7 @@ package myerr
import (
"fmt"
"git.hilo.cn/hilo-common/myerr"
"git.hilo.cn/hilo-common/mylogrus"
"github.com/pkg/errors"
"strconv"
......@@ -226,35 +227,10 @@ func WrapErr(err error) error {
}
}
func WrapGameErr(err error) error {
if err == nil {
return err
}
if h, ok := err.(*GameError); ok {
return h
}
return NewGameError(500, err.Error())
}
// 系统错误
type GameError struct {
code uint16
message string
err error
}
func (err *GameError) Error() string {
return err.err.Error()
}
func (err *GameError) Code() uint16 {
return err.code
}
func NewGameError(code uint16, msg string) *GameError {
return &GameError{
code: code,
message: msg,
err: errors.New("{code:" + strconv.Itoa(int(code)) + ",message:" + msg + "}"),
func ToLocal(err *myerr.BusinessError) error {
return &BusinessError{
code: err.GetCode(),
message: err.GetMsg(),
err: err.GetErr(),
}
}
CREATE TABLE `cp_relation` (
`id` bigint unsigned AUTO_INCREMENT NOT NULL,
`user_id1` bigint NOT NULL COMMENT 'user_id1',
`user_id2` bigint NOT NULL COMMENT 'user_id2',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uid1_idx` (`user_id1`) USING BTREE,
UNIQUE KEY `uid2_idx` (`user_id2`) USING BTREE,
KEY `ctime_idx` (`created_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp关系表';
INSERT INTO hilo.diamond_operate_set (diamond_num, frequency_num, frequency_day, diamond_max_num, add_reduce, `type`, name, status, diamond_type)
VALUES (-1, -1, -1, -1, 2, 94, 'cp邀请扣费', 1, 1),
(-1, -1, -1, -1, 1, 95, 'cp邀请退费', 1, 1);
CREATE TABLE `cp_invite` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '发起邀请者',
`invite_user_id` bigint NOT NULL COMMENT '被邀请的人',
`diamond_num` int unsigned NOT NULL COMMENT '邀请者花费的钻石',
`status` tinyint unsigned NOT NULL COMMENT '状态1.未接受2.已接受3.拒接导致退费4.过期导致退费',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `uid_idx` (`user_id`) USING BTREE,
KEY `uid2_idx` (`invite_user_id`) USING BTREE,
KEY `status_idx` (`status`) USING BTREE,
KEY `created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp邀请发起记录';
CREATE TABLE `cp_cancel` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '发起者',
`rec_user_id` bigint NOT NULL COMMENT '接收者',
`status` tinyint unsigned NOT NULL COMMENT '状态1.未处理2.发起者已撤销3.对方已确认4.到期自动确认',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `uid_idx` (`user_id`) USING BTREE,
KEY `uid2_idx` (`rec_user_id`) USING BTREE,
KEY `status_idx` (`status`) USING BTREE,
KEY `created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp解除发起记录';
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (242, 'zh', '仅限送给CP'),
(242, 'en', 'Only for CP'),
(242, 'ar', 'فقط من أجل CP'),
(242, 'tr', 'Sadece CP için'),
(242, 'id', 'Hanya untuk CP'),
(242, 'ru', 'Только для КП'),
(242, 'ko', 'CP 전용'),
(242, 'pt', 'Somente para CP'),
(242, 'th', 'สำหรับซีพีเท่านั้น'),
(242, 'ca', 'Solo para CP'),
(242, 'hi', 'केवल सीपी के लिए'),
(242, 'vi', 'Chỉ dành cho CP'),
(242, 'ur', 'صرف CP کے لیے');
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (243, 'zh', '对方已有CP了'),
(243, 'en', 'The opponent already has CP'),
(243, 'ar', 'الطرف الآخر لديه بالفعل CP'),
(243, 'tr', "Rakibin zaten CP'si var"),
(243, 'id', 'Lawan sudah memiliki CP'),
(243, 'ru', 'У противника уже есть CP'),
(243, 'ko', '상대는 이미 CP를 가지고 있습니다.'),
(243, 'pt', 'O oponente já tem CP'),
(243, 'th', 'ฝ่ายตรงข้ามมี CP อยู่แล้ว'),
(243, 'ca', 'El oponente ya tiene CP'),
(243, 'hi', 'विरोधी के पास पहले से ही CP है'),
(243, 'vi', 'Đối thủ đã có CP'),
(243, 'ur', 'مخالف کے پاس پہلے ہی سی پی ہے۔');
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (244, 'zh', "你想要和我成为CP吗?"),
(244, 'en', "Do you want to be CP with me?"),
(244, 'ar', "هل ترغب في ان تكون CP الخاص معي؟"),
(244, 'tr', "Benimle CP olmak ister misin?"),
(244, 'id', "Apakah Anda ingin menjadi CP dengan saya?"),
(244, 'ru', "Хочешь быть со мной?"),
(244, 'ko', "나랑 CP할래?"),
(244, 'pt', "Você quer ser CP comigo?"),
(244, 'th', "อยากเป็น CP กับฉันไหม?"),
(244, 'ca', "¿Quieres ser CP conmigo?"),
(244, 'hi', "क्या आप मेरे साथ सीपी बनना चाहते हैं?"),
(244, 'vi', "Bạn có muốn trở thành CP với tôi không?"),
(244, 'ur', "کیا آپ میرے ساتھ CP بننا چاہتے ہیں؟");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (245, 'zh', "我想成为你的CP"),
(245, 'en', "I want to be your CP"),
(245, 'ar', "أريد أن أكون CP الخاص بك"),
(245, 'tr', "senin CP'n olmak istiyorum"),
(245, 'id', "Saya ingin menjadi CP Anda"),
(245, 'ru', "Я хочу быть твоим CP"),
(245, 'ko', "당신의 CP가 되고 싶습니다"),
(245, 'pt', "quero ser seu cp"),
(245, 'th', "ฉันอยากเป็นซีพีของคุณ"),
(245, 'ca', "quiero ser tu CP"),
(245, 'hi', "मैं आपका सीपी बनना चाहता हूं"),
(245, 'vi', "Tôi muốn trở thành CP của bạn"),
(245, 'ur', "میں آپ کا CP بننا چاہتا ہوں۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (246, 'zh', "24小时后自动失效"),
(246, 'en', "Automatically expires after 24 hours"),
(246, 'ar', "تنتهي الصلاحية تلقائيًا بعد 24 ساعة"),
(246, 'tr', "24 saat sonra otomatik olarak sona erer"),
(246, 'id', "Secara otomatis kedaluwarsa setelah 24 jam"),
(246, 'ru', "Автоматически истекает через 24 часа"),
(246, 'ko', "24시간 후 자동 만료"),
(246, 'pt', "Expira automaticamente após 24 horas"),
(246, 'th', "หมดอายุโดยอัตโนมัติหลังจาก 24 ชั่วโมง"),
(246, 'ca', "Caduca automáticamente después de 24 horas"),
(246, 'hi', "24 घंटे के बाद स्वतः समाप्त हो जाता है"),
(246, 'vi', "Tự động hết hạn sau 24 giờ"),
(246, 'ur', "24 گھنٹے کے بعد خود بخود ختم ہو جاتا ہے۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (247, 'zh', "我想解绑CP"),
(247, 'en', "I want to unbind CP"),
(247, 'ar', "أريد فك ارتباط CP"),
(247, 'tr', "CP bağlantısını kaldırmak istiyorum"),
(247, 'id', "Saya ingin melepaskan CP"),
(247, 'ru', "Я хочу отвязать CP"),
(247, 'ko', "CP 바인딩을 해제하고 싶습니다."),
(247, 'pt', "quero desvincular o CP"),
(247, 'th', "ฉันต้องการยกเลิกการเชื่อมโยง CP"),
(247, 'ca', "Quiero desvincular CP"),
(247, 'hi', "मैं सीपी को खोलना चाहता हूं"),
(247, 'vi', "Tôi muốn hủy liên kết CP"),
(247, 'ur', "میں CP کو بند کرنا چاہتا ہوں۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (248, 'zh', "我们已经是CP了!"),
(248, 'en', "We are already CP!"),
(248, 'ar', "أصبحنا CP!"),
(248, 'tr', "Biz zaten CP'yiz!"),
(248, 'id', "Kami sudah CP!"),
(248, 'ru', "Мы уже КП!"),
(248, 'ko', "우리는 이미 CP입니다!"),
(248, 'pt', "Já somos CP!"),
(248, 'th', "เราเป็นซีพีแล้ว!"),
(248, 'ca', "¡Ya somos CP!"),
(248, 'hi', "हम पहले से ही सीपी हैं!"),
(248, 'vi', "Chúng ta đã là CP rồi!"),
(248, 'ur', "ہم پہلے ہی CP ہیں!");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (249, 'zh', "庆祝礼物已发送到%s的背包"),
(249, 'en', "Celebration gifts have been sent to %s 's backpack"),
(249, 'ar', "تم إرسال هدايا الاحتفال إلى حقيبة %s"),
(249, 'tr', "%s'nin sırt çantasına kutlama hediyeleri gönderildi"),
(249, 'id', "Hadiah perayaan telah dikirim ke ransel %s"),
(249, 'ru', "Праздничные подарки отправлены в рюкзак %s."),
(249, 'ko', "축하 선물이 %s의 배낭으로 보내졌습니다."),
(249, 'pt', "Presentes de comemoração foram enviados para a mochila de %s"),
(249, 'th', "ของขวัญฉลองถูกส่งไปที่กระเป๋าเป้สะพายหลังของ %s แล้ว"),
(249, 'ca', "Se han enviado regalos de celebración a la mochila de %s"),
(249, 'hi', "उत्सव उपहार %s के बैकपैक में भेज दिए गए हैं"),
(249, 'vi', "Quà kỷ niệm đã được gửi tới ba lô của %s'"),
(249, 'ur', "جشن کے تحائف %s کے بیگ میں بھیجے گئے ہیں۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (250, 'zh', "%s已拒绝CP邀请"),
(250, 'en', "%s has rejected the CP invitation"),
(250, 'ar', "%s رفض دعوة CP"),
(250, 'tr', "%s CP davetini reddetti"),
(250, 'id', "%s telah menolak undangan CP"),
(250, 'ru', "%s отклонил приглашение CP"),
(250, 'ko', "%s님이 CP 초대를 거부했습니다."),
(250, 'pt', "%s rejeitou o convite CP"),
(250, 'th', "%s ได้ปฏิเสธคำเชิญ CP"),
(250, 'ca', "%s ha rechazado la invitación de CP"),
(250, 'hi', "%s ने CP आमंत्रण को अस्वीकार कर दिया है"),
(250, 'vi', "%s đã từ chối lời mời CP"),
(250, 'ur', "%s نے CP دعوت نامے کو مسترد کر دیا ہے۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (251, 'zh', "已解绑CP,CP值被清空,CP特权已消失"),
(251, 'en', "The CP has been unbound, the CP points has been cleared, and the CP privilege has disappeared"),
(251, 'ar', "تم فك ارتباط CP ، وتم مسح نقاط CP ، واختفيت امتيازات CP"),
(251, 'tr', "CP bağlantısı kaldırıldı, CP puanları silindi ve CP ayrıcalığı kayboldu"),
(251, 'id', "CP telah dilepas, poin CP telah dihapus, dan hak istimewa CP telah hilang"),
(251, 'ru', "CP был развязан, CP-очки были очищены, а привилегия CP исчезла."),
(251, 'ko', "CP가 해제되고 CP 포인트가 해제되며 CP 특권이 사라졌습니다."),
(251, 'pt', "O CP foi desvinculado, os pontos do CP foram apagados e o privilégio do CP desapareceu"),
(251, 'th', "CP ไม่ถูกผูกมัด คะแนน CP ถูกล้าง และสิทธิ์ CP หายไป"),
(251, 'ca', "El CP se ha desvinculado, los puntos de CP se han borrado y el privilegio de CP ha desaparecido"),
(251, 'hi', "सीपी अनबाउंड हो गया है, सीपी पॉइंट क्लियर हो गए हैं, और सीपी विशेषाधिकार गायब हो गया है"),
(251, 'vi', "CP đã bị hủy liên kết, điểm CP đã bị xóa và đặc quyền CP đã biến mất"),
(251, 'ur', "CP کو غیر پابند کر دیا گیا ہے، CP پوائنٹس کو صاف کر دیا گیا ہے، اور CP کا استحقاق غائب ہو گیا ہے");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (258, 'zh', "已经过期"),
(258, 'en', "Already expired"),
(258, 'ar', "تم انتهاء صلاحيتها"),
(258, 'tr', "Zaten süresi dolmuş"),
(258, 'id', "Sudah kedaluwarsa"),
(258, 'ru', "Срок действия уже истек"),
(258, 'ko', "이미 만료됨"),
(258, 'pt', "Já expirou"),
(258, 'th', "หมดอายุแล้ว"),
(258, 'ca', "ya vencido"),
(258, 'hi', "पहले ही समाप्त हो चुका है"),
(258, 'vi', "Đã hết hạn"),
(258, 'ur', "پہلے ہی ختم ہو چکا ہے۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (272, 'zh', "绑定CP花费"),
(272, 'en', "Binding CP cost"),
(272, 'ar', "تكلفة CP الارتباط"),
(272, 'tr', "Bağlayıcı CP maliyeti"),
(272, 'id', "Mengikat biaya CP"),
(272, 'ru', "Привязка стоимости CP"),
(272, 'ko', "구속력 있는 CP 비용"),
(272, 'pt', "Custo de CP vinculativo"),
(272, 'th', "ค่าซีพีเข้าเล่ม"),
(272, 'ca', "Costo de CP vinculante"),
(272, 'hi', "बाध्यकारी सीपी लागत"),
(272, 'vi', "Chi phí CP ràng buộc"),
(272, 'ur', "بائنڈنگ CP لاگت");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (273, 'zh', "绑定CP返还"),
(273, 'en', "Binding CP return"),
(273, 'ar', "استرداد CP الارتباط"),
(273, 'tr', "Bağlayıcı CP dönüşü"),
(273, 'id', "Pengembalian CP yang mengikat"),
(273, 'ru', "Обязательный возврат CP"),
(273, 'ko', "바인딩 CP 반환"),
(273, 'pt', "Retorno de CP vinculativo"),
(273, 'th', "การคืนค่า CP ที่มีผลผูกพัน"),
(273, 'ca', "Retorno de CP vinculante"),
(273, 'hi', "बाध्यकारी सीपी वापसी"),
(273, 'vi', "Lợi nhuận CP ràng buộc"),
(273, 'ur', "بائنڈنگ CP واپسی۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (274, 'zh', "%s撤销了解绑CP的申请"),
(274, 'en', "%s canceled the application to unbind CP"),
(274, 'ar', "%s قام بسحب طلبه لفك ارتباط CP"),
(274, 'tr', "%s, CP'nin bağlantısını kaldırma başvurusunu iptal etti"),
(274, 'id', "%s membatalkan aplikasi untuk melepaskan CP"),
(274, 'ru', "%s отменил заявку на отвязку CP"),
(274, 'ko', "%s이(가) CP 바인딩 해제 신청을 취소했습니다."),
(274, 'pt', "%s cancelou o aplicativo para desvincular CP"),
(274, 'th', "%s ยกเลิกแอปพลิเคชันเพื่อยกเลิกการเชื่อมโยง CP"),
(274, 'ca', "%s canceló la solicitud para desvincular CP"),
(274, 'hi', "%s ने सीपी को अनबाइंड करने के लिए आवेदन को रद्द कर दिया"),
(274, 'vi', "%s đã hủy đơn đăng ký hủy liên kết CP"),
(274, 'ur', "%s نے CP کی پابندی ختم کرنے کے لیے درخواست منسوخ کر دی۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (275, 'zh', "等待对方接受"),
(275, 'en', "Waiting to be accepted"),
(275, 'ar', "في انتظار قبول الطرف الآخرى"),
(275, 'tr', "Kabul edilmeyi bekliyorum"),
(275, 'id', "Menunggu untuk diterima"),
(275, 'ru', "Ожидание принятия"),
(275, 'ko', "수락 대기 중"),
(275, 'pt', "Esperando ser aceito"),
(275, 'th', "รอรับได้เลยครับ"),
(275, 'ca', "Esperando ser aceptado"),
(275, 'hi', "स्वीकार किए जाने की प्रतीक्षा कर रहा है"),
(275, 'vi', "Chờ đợi để được chấp nhận"),
(275, 'ur', "قبول ہونے کا انتظار ہے۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (276, 'zh', "邀请被接受"),
(276, 'en', "Invitation accepted"),
(276, 'ar', "تم قبول الدعوة"),
(276, 'tr', "davet kabul edildi"),
(276, 'id', "undangan diterima"),
(276, 'ru', "приглашение принято"),
(276, 'ko', "초대 수락됨"),
(276, 'pt', "convite aceito"),
(276, 'th', "ยอมรับคำเชิญแล้ว"),
(276, 'ca', "invitación aceptada"),
(276, 'hi', "निमंत्रण स्वीकार किया"),
(276, 'vi', "lời mời được chấp nhận"),
(276, 'ur', "دعوت قبول کی");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (277, 'zh', "邀请被拒绝"),
(277, 'en', "Invitation refused"),
(277, 'ar', "تم رفض الدعوة"),
(277, 'tr', "davet reddedildi"),
(277, 'id', "undangan ditolak"),
(277, 'ru', "приглашение отклонено"),
(277, 'ko', "초대가 거부됨"),
(277, 'pt', "convite recusado"),
(277, 'th', "คำเชิญถูกปฏิเสธ"),
(277, 'ca', "invitación rechazada"),
(277, 'hi', "निमंत्रण अस्वीकार कर दिया"),
(277, 'vi', "lời mời từ chối"),
(277, 'ur', "دعوت سے انکار کر دیا");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (278, 'zh', "已解绑CP"),
(278, 'en', "CP has been unbound"),
(278, 'ar', "تم فك علاقة CP"),
(278, 'tr', "CP bağlantısı kaldırıldı"),
(278, 'id', "CP telah dilepaskan"),
(278, 'ru', "CP не привязан"),
(278, 'ko', "CP가 언바운드되었습니다."),
(278, 'pt', "CP foi desvinculado"),
(278, 'th', "CP หลุดแล้ว"),
(278, 'ca', "CP ha sido desvinculado"),
(278, 'hi', "सीपी अनबाउंड किया गया है"),
(278, 'vi', "CP không bị ràng buộc"),
(278, 'ur', "سی پی کو غیر پابند کیا گیا ہے۔");
INSERT INTO hilo.res_multi_text (msg_id, `language`, content)
VALUES (279, 'zh', "已被取消"),
(279, 'en', "Has been canceled"),
(279, 'ar', "تم الإلغاء"),
(279, 'tr', "İptal edildi"),
(279, 'id', "Telah dibatalkan"),
(279, 'ru', "Была отменена"),
(279, 'ko', "취소되었습니다"),
(279, 'pt', "Foi cancelado"),
(279, 'th', "ถูกยกเลิก"),
(279, 'ca', "Ha sido cancelado"),
(279, 'hi', "रद्द किया गया"),
(279, 'vi', "Đã hủy bỏ"),
(279, 'ur', "منسوخ کر دیا گیا ہے۔");
......@@ -10,6 +10,18 @@ import (
"hilo-user/myerr/bizerr"
)
// 分页base
type PageReqBase struct {
PageIndex int `form:"pageIndex,default=0"`
PageSize int `form:"pageSize,default=10"`
}
type PageRespBase struct {
NextPageIndex int `json:"nextPageIndex"`
HasNextPage bool `json:"hasNextPage"`
Data interface{} `json:"data"` // 需要具体自定义
}
func GetUserId(c *gin.Context) (mysql.ID, error) {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
......@@ -18,6 +30,20 @@ func GetUserId(c *gin.Context) (mysql.ID, error) {
return 0, bizerr.ParaMissing
}
func ToUserId(myContext *mycontext.MyContext, externalId mysql.Str) (mysql.ID, error) {
return user_c.ToUserId(domain.CreateModelContext(myContext), externalId)
//if externalId == "" {
// return 0, myerr.NewSysError("externalId 不能为空")
//}
//var user user_m.User
//if err := mysql.Db.Where(&user_m.User{
// ExternalId: externalId,
//}).First(&user).Error; err != nil {
// return 0, bizerr.ExternalIdNoExist
//}
//return user.ID, nil
}
// 获取userId和externalId
func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
......
......@@ -5,6 +5,7 @@ import (
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
"hilo-user/myerr"
"hilo-user/req"
"net/http"
)
......@@ -42,27 +43,23 @@ func ResponseOk(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, response)
}
func GameResponseOk(c *gin.Context, data interface{}) {
// always return http.StatusOK
response := GameResponse{
RetCode: 0,
RetMsg: myerr.GetSuccessMsg(),
SdkErrorCode: 0,
Data: data,
// 分页返回
// 客户端入参 req.PageReqBase
// 服务端返回 req.PageRespBase
func ResponsePageBaseOk(c *gin.Context, data interface{}, nextPageIndex int, hasNextPage bool) {
if data == nil {
data = make([]interface{}, 0)
}
printResponseBody(c, &response)
c.JSON(http.StatusOK, response)
}
func GameResponseFail(c *gin.Context, err *myerr.GameError) {
// always return http.StatusOK
response := GameResponse{
RetCode: err.Code(),
RetMsg: err.Error(),
SdkErrorCode: err.Code(),
Data: nil,
response := Response{
Code: myerr.GetSuccessCode(),
Message: myerr.GetSuccessMsg(),
OperationMessage: myerr.GetSuccessMsg(),
Data: req.PageRespBase{
NextPageIndex: nextPageIndex,
HasNextPage: hasNextPage,
Data: data,
},
}
printResponseBody(c, &response)
c.JSON(http.StatusOK, response)
}
......
package cp_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"strconv"
)
type PostPutAnniversaryReq struct {
Content string `form:"content" binding:"required"`
Timestamp int64 `form:"timestamp" binding:"required"`
IsRemind bool `form:"isRemind"`
}
// @Tags CP v2
// @Summary 发布纪念日
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param content formData string true "纪念日名称"
// @Param timestamp formData int true "时间戳"
// @Param isRemind formData bool false "是否提醒"
// @Success 200
// @Router /v2/cp/anniversary [post]
func PostAnniversary(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
var param PostPutAnniversaryReq
if err := c.ShouldBind(&param); err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
relation, exits := cp_m.GetCpRelation(model, userId)
if !exits {
return myCtx, bizerr.CpNotRelation
} else {
if err := cp_m.AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, relation, param.Content, param.Timestamp, param.IsRemind, 0); err != nil {
return myCtx, err
}
}
resp.ResponseOk(c, "")
return myCtx, nil
}
// @Tags CP v2
// @Summary 修改纪念日
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param content formData string true "纪念日名称"
// @Param timestamp formData int true "时间戳"
// @Param isRemind formData bool false "是否提醒"
// @Param id path int true "更新的记录id"
// @Success 200
// @Router /v2/cp/anniversary/{id} [put]
func PutAnniversary(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var param PostPutAnniversaryReq
if err := c.ShouldBind(&param); err != nil {
return myCtx, err
}
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
model := domain.CreateModelContext(myCtx)
if err := cp_m.UpdateCpAnniversary(model, id, param.Content, param.Timestamp, param.IsRemind); err != nil {
return myCtx, err
}
resp.ResponseOk(c, "")
return myCtx, nil
}
// @Tags CP v2
// @Summary 获取纪念日
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageIndex query int true "偏移值 默认:1" default(1)
// @Param pageSize query int true "请求数量 默认:10" default(10)
// @Success 200 {object} []cp_cv.CvCpAnniversary
// @Router /v2/cp/anniversary [get]
func PageAnniversary(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
var response = make([]cp_cv.CvCpAnniversary, 0)
model := domain.CreateModelContext(myCtx)
cpRelation, exits := cp_m.GetCpRelation(model, userId)
if exits {
userIds := []uint64{cpRelation.UserId1, cpRelation.UserId2}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myCtx, err
}
cpUserId := cpRelation.UserId2
if cpUserId == userId {
cpUserId = cpRelation.UserId1
}
userInfo := user_cv.UserToTiny(users[userId])
cpUserInfo := user_cv.UserToTiny(users[cpUserId])
response = append(response, cp_cv.CvCpAnniversary{
Type: cp_e.AnniversaryItemTypeAvatar,
CpInfo: &cp_cv.CvCpBase{
UserInfo: *userInfo,
CpUserInfo: *cpUserInfo,
},
OriginTimestamp: cpRelation.CreatedTime.Unix(),
Timestamp: cpRelation.CreatedTime.Unix(),
CanDel: false,
})
}
anniversary := cp_m.GetAllCpAnniversary(model, userId)
for _, v := range anniversary {
timestamp := v.Timestamp
if v.Type == cp_e.AnniversaryItemTypeAnniversary && timestamp > 0 {
timestamp = cp_m.CalcNextAnniversary(timestamp)
}
// 客户端只认识0 1
Type := v.Type
if v.Type != cp_e.AnniversaryItemTypeAvatar {
Type = cp_e.AnniversaryItemTypeNormal
}
response = append(response, cp_cv.CvCpAnniversary{
Type: Type,
Id: v.ID,
Content: v.Content,
Timestamp: timestamp,
OriginTimestamp: v.Timestamp,
IsRemind: v.IsRemind,
CanDel: true,
IsTop: v.Sort > 0,
})
}
resp.ResponsePageBaseOk(c, response, 0, false)
return myCtx, nil
}
// @Tags CP v2
// @Summary 获取纪念日
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param id path int true "记录id"
// @Success 200
// @Router /v2/cp/anniversary/:id [delete]
func DelAnniversary(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
model := domain.CreateModelContext(myCtx)
if err := cp_m.DelCpAnniversary(model, id); err != nil {
return myCtx, err
}
resp.ResponseOk(c, "")
return myCtx, nil
}
package cp_r
import (
"encoding/json"
"fmt"
"git.hilo.cn/hilo-common/_const/common"
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/_const/enum/msg_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/myerr/comerr"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/txop/bag_tx"
"git.hilo.cn/hilo-common/txop/diamond_tx"
"git.hilo.cn/hilo-common/txop/headwear_tx"
"git.hilo.cn/hilo-common/txop/msg"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/cache/user_c"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/user_m"
"hilo-user/domain/service/cp_s"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"strconv"
"time"
)
// @Tags cp关系
// @Summary 检查用户是否绑定了cp
// @Param externalId query string true "用户的externalId"
// @Success 200 {object} cp_cv.CheckCpRelationRes
// @Router /v2/cp/relation/check [get]
func CheckUserCpRelation(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
externalId := c.Query("externalId")
if externalId == "" {
return myCtx, bizerr.InvalidParameter
}
_, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
if externalId == "" {
return myCtx, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myCtx, err
}
cp, err := cp_m.GetCp(model, user.ID)
if err != nil {
return myCtx, err
}
if cp.Id > 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_HAS_CP, lang, comerr.AlreadyHasCp))
}
msg, err := msg.GetResMultiTextBy(model, common.MSG_ID_INVITE_CP, lang)
if err != nil {
return myCtx, err
}
resp.ResponseOk(c, cp_cv.CheckCpRelationRes{Diamond: cp_e.CpRelationInviteDiamond, Msg: msg})
return myCtx, nil
}
// @Tags cp关系
// @Summary 发送cp邀请/发起解除cp
// @Param externalId formData string true "对方的externalId"
// @Param type formData int true "类型1.发起邀请2.发起解除"
// @Success 200
// @Router /v2/cp/relation [post]
func CpRelation(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
externalId := c.PostForm("externalId")
if externalId == "" {
return myCtx, bizerr.InvalidParameter
}
myUserId, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
optType, err := strconv.Atoi(c.PostForm("type"))
if err != nil || optType > 2 || optType < 1 {
return myCtx, bizerr.InvalidParameter
}
if optType == 1 { // 邀请
err = cp_s.InviteCpRelation(myCtx, myUserId, externalId, lang)
if err != nil {
myCtx.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return myCtx, err
}
} else {
// 发起解除
err = cp_s.CancelCpRelation(myCtx, myUserId, externalId, lang)
if err != nil {
myCtx.Log.Errorf("CancelCpRelation myUserId:%d, err:%v", myUserId, err)
return myCtx, err
}
}
resp.ResponseOk(c, nil)
return myCtx, nil
}
// @Tags cp关系
// @Summary 回应cp邀请
// @Param externalId formData string true "对方用户的externalId"
// @Param type formData int true "类型1.接受2.拒绝"
// @Success 200
// @Router /v2/cp/relation/invite/reply [post]
func ReplyCpInvite(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
externalId := c.PostForm("externalId")
if externalId == "" {
return myCtx, myerr.WrapErr(bizerr.InvalidParameter)
}
optType, err := strconv.Atoi(c.PostForm("type"))
if err != nil || optType > 2 || optType < 1 {
return myCtx, myerr.WrapErr(bizerr.InvalidParameter)
}
myUserId, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return myCtx, err
}
userSender, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myCtx, err
}
if userSender.ID == myUserId {
return myCtx, myerr.WrapErr(bizerr.InvalidParameter)
}
cpRecord, err := cp_m.GetCpInvite(model, userSender.ID, user.ID, cp_e.CpInvite)
if err != nil {
model.Log.Errorf("ReplyCpInvite userSender:%d, user:%d, err:%v", userSender.ID, user.ID, err)
return myCtx, err
}
if cpRecord == nil || cpRecord.Id == 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_EXPIRED, lang, comerr.AlreadyExpired))
}
if optType == 1 { // 接受的时候
// 自己是否有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return myCtx, err
}
if myCp.Id > 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_HAS_CP, lang, comerr.AlreadyHasCp))
}
// 对方是否已经有cp了
senderCp, err := cp_m.GetCp(model, userSender.ID)
if err != nil {
return myCtx, err
}
if senderCp.Id > 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_HAS_CP, lang, comerr.AlreadyHasCp))
}
}
err = model.Transaction(func(model *domain.Model) error {
// 更新邀请状态
updateStatus := cp_e.CpInviteAccept
if optType == 2 { // 拒接
updateStatus = cp_e.CpInviteRefuse
}
err = cp_m.UpdateStatusCpInvite(model, cpRecord.Id, updateStatus)
if err != nil {
model.Log.Errorf("ReplyCpInvite userSender:%d, user:%d, status:%d, err:%v", userSender.ID, user.ID, updateStatus, err)
return err
}
var msgData []byte
if optType == 1 { // 接受
// 写入cp关系表
cpId, err := cp_m.CreateCp(model, userSender.ID, user.ID)
if err != nil {
model.Log.Errorf("ReplyCpInvite userSender:%d, user:%d, status:%d, err:%v", userSender.ID, user.ID, updateStatus, err)
return err
}
// 初始化cp等级
if err := cp_m.InitCpLevel(model, mysql.ID(cpId), userSender.ID, user.ID); err != nil {
model.Log.Errorf("ReplyCpInvite InitCpLevel fail:%v-%v-%v", userSender.ID, user.ID, err)
return err
}
// 初始化cp纪念日
if err := cp_m.InitCpAnniversary(model, cp_m.CpRelation{
Id: mysql.ID(cpId),
UserId1: userSender.ID,
UserId2: user.ID,
}, lang); err != nil {
model.Log.Errorf("ReplyCpInvite InitCpAnniversary fail:%v-%v-%v", userSender.ID, user.ID, err)
return err
}
// 发放告白礼物
if _, err = bag_tx.SendUserBag(model, userSender.ID, 1, cp_e.CpConfessionGiftId, 1, 3, "告白礼物"); err != nil {
model.Log.Errorf("ReplyCpInvite userSender:%d, user:%d, status:%d, err:%v", userSender.ID, user.ID, updateStatus, err)
return err
}
// 发放头饰
for _, u := range []*user_m.User{userSender, user} {
headwearId := cp_e.CpMaleHeadwearId
if u.Sex == mysql.WOMAN {
headwearId = cp_e.CpFemaleHeadwearId
}
if err = headwear_tx.SendHeadwear(model, u.ID, mysql.ID(headwearId), 3000); err != nil {
model.Log.Errorf("ReplyCpInvite user:%d, headwearId:%d, err:%v", u.ID, headwearId, err)
return err
}
}
// 私信-接受
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_BIND_CP_SUCCEED, lang)
if err != nil {
return err
}
tip, err := msg.GetResMultiTextBy(model, common.MSG_ID_SEND_CP_GIFT, lang)
if err != nil {
return err
}
msgData, _ = json.Marshal(cp_m.CpAcceptInviteMessage{
Identifier: "CpAcceptInviteMessage",
Msg: content,
Tip: fmt.Sprintf(tip, userSender.Code),
Sender: user_m.ToUserTiny(userSender),
Receiver: user_m.ToUserTiny(user),
})
} else { // 拒绝
// 退费
err = diamond_tx.SendDiamond(model, cpRecord.UserId, diamond_e.CpInviteRefund, cpRecord.Id, cpRecord.DiamondNum,
msg_e.MgrSendDiamondProperty)
if err != nil {
model.Log.Errorf("ReplyCpInvite UserId:%d, err:%v", cpRecord.UserId, err)
return err
}
// 私信-拒绝
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_REJECTED_CP_INVITE, lang)
if err != nil {
return err
}
msgData, _ = json.Marshal(cp_m.CpDenyInviteMessage{
Identifier: "CpDenyInviteMessage",
Msg: fmt.Sprintf(content, user.Nick),
Sender: user_m.ToUserTiny(user),
})
}
if err := tencentyun.BatchSendCustomMsg(model, 1, userSender.ExternalId, []string{user.ExternalId}, string(msgData), "cp邀请"); err != nil {
model.Log.Errorf("BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("ReplyCpInvite myUserId:%d, err:%v", myUserId, err)
return myCtx, err
}
resp.ResponseOk(c, nil)
return myCtx, nil
}
// @Tags cp关系
// @Summary 回应cp解除
// @Param externalId formData string true "对方的externalId"
// @Param type formData int true "类型1.撤销2.接受"
// @Success 200
// @Router /v2/cp/relation/cancel/reply [post]
func ReplyCpCancel(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
externalId := c.PostForm("externalId")
if externalId == "" {
return myCtx, bizerr.InvalidParameter
}
optType, err := strconv.Atoi(c.PostForm("type"))
if err != nil || optType > 2 || optType < 1 {
return myCtx, bizerr.InvalidParameter
}
myUserId, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
myUser, err := user_m.GetUser(model, myUserId)
if err != nil {
return myCtx, err
}
user2, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myCtx, err
}
if user2.ID == myUserId {
return myCtx, bizerr.InvalidParameter
}
cpCancel, err := cp_m.GetCpCancel(model, []uint64{myUser.ID, user2.ID}, cp_e.CpCancel)
if err != nil {
model.Log.Errorf("ReplyCpCancel myUser:%d, user2:%d, err:%v", myUser.ID, user2.ID, err)
return myCtx, err
}
if cpCancel == nil || cpCancel.Id == 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, common.MSG_ID_ALREADY_EXPIRED, lang, comerr.AlreadyExpired))
}
if optType == 1 { // 撤销,只有自己能撤销自己的申请
if cpCancel.UserId != myUserId {
return myCtx, bizerr.InvalidParameter
}
} else { // 接受,只有对方能接受
if cpCancel.RecUserId != myUserId {
return myCtx, bizerr.InvalidParameter
}
}
err = model.Transaction(func(model *domain.Model) error {
// 更新邀请状态
updateStatus := cp_e.CpCancelRevoke
if optType == 2 { // 接受
updateStatus = cp_e.CpCancelAccept
}
err = cp_m.UpdateStatusCpCancel(model, cpCancel.Id, updateStatus)
if err != nil {
model.Log.Errorf("ReplyCpCancel myUser:%d, user2:%d, status:%d, err:%v", myUser.ID, user2.ID, updateStatus, err)
return err
}
var msgData []byte
if optType == 1 { // 撤销解除
// 私信
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_CANCEL_UNBIND_CP, lang)
if err != nil {
return err
}
msgData, _ = json.Marshal(cp_m.CpDealCancelMessage{
Identifier: "CpDealCancelMessage",
Msg: fmt.Sprintf(content, myUser.Nick),
Status: 1,
})
} else { // 接受解除
// 删除cp关系表的记录
err = cp_m.DelCpRelation(model, myUser.ID, user2.ID)
if err != nil {
model.Log.Errorf("ReplyCpCancel myUser:%d, user2:%d, status:%d, err:%v", myUser.ID, user2.ID, updateStatus, err)
return err
}
// 私信-接受解除
content, err := msg.GetResMultiTextBy(model, common.MSG_ID_UNBIND_CP_SUCCEED, lang)
if err != nil {
return err
}
msgData, _ = json.Marshal(cp_m.CpDealCancelMessage{
Identifier: "CpDealCancelMessage",
Msg: content,
Status: 2,
})
// 删除cp头饰
_ = headwear_tx.DelHeadwear(model, myUser.ID, cp_e.CpHeadwearId)
_ = headwear_tx.DelHeadwear(model, user2.ID, cp_e.CpHeadwearId)
}
if err := tencentyun.BatchSendCustomMsg(model, 1, myUser.ExternalId, []string{user2.ExternalId}, string(msgData), "cp解除"); err != nil {
model.Log.Errorf("ReplyCpCancel BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("ReplyCpCancel myUserId:%d, err:%v", myUserId, err)
return myCtx, err
}
resp.ResponseOk(c, cp_cv.CheckCpRelationRes{})
return myCtx, nil
}
type CpDetail struct {
CpInfo cp_cv.CvCpInfo `json:"cpInfo"` // cp信息
CpLevel cp_cv.CvCpLevel `json:"cpLevel"` // cp等级
}
// @Tags cp关系
// @Summary 详情页cp数据
// @Param externalId query string true "用户的externalId"
// @Success 200 {object} CpDetail
// @Router /v2/cp/relation/detail [get]
func CpDetailPage(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
externalId := c.Query("externalId")
if externalId == "" {
return myCtx, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myCtx, err
}
if user == nil || user.ID == 0 {
return myCtx, bizerr.InvalidParameter
}
cp, err := cp_m.GetCp(model, user.ID)
if err != nil {
return myCtx, err
}
var res *CpDetail
if cp.Id > 0 {
userIds := []uint64{cp.UserId1, cp.UserId2}
userMap, err := user_c.GetUserTinyMap(model, userIds, false)
if err != nil {
return myCtx, err
}
res = new(CpDetail)
// 返回值
level := cp_m.GetCpLevel(model, cp.Id)
if level.ID > 0 {
res.CpLevel = cp_cv.CvCpLevel{
Level: level.Level,
Points: cp_e.CpLevelPoints[level.Level] + level.Points,
StartPoints: cp_e.CpLevelPoints[level.Level],
ExpireAtUnix: level.ExpireAt.Unix(),
SettlementDate: level.ExpireAt.Format(utils.DATE_FORMAT),
}
}
if res.CpLevel.Level != cp_e.CpLevelMax {
res.CpLevel.EndPoints = cp_e.CpLevelPoints[res.CpLevel.Level+1]
}
res.CpInfo = cp_cv.CvCpInfo{
UserInfo: user_cv.UserTinyToCvTiny(userMap[cp.UserId1]),
CpUserInfo: user_cv.UserTinyToCvTiny(userMap[cp.UserId2]),
CpDays: int(time.Now().Sub(cp.CreatedTime).Hours()/24) + 1,
CreatedUnix: cp.CreatedTime.Unix(),
}
}
resp.ResponseOk(c, res)
return myCtx, nil
}
// @Tags cp关系
// @Summary 检查cp的im是否失效
// @Param msgType query int true "类型"
// @Param msgId query int true "消息id"
// @Success 200 {object} cp_cv.CheckCpImRes
// @Router /v2/cp/im/check [get]
func CheckCpImExpire(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
msgType, err := strconv.Atoi(c.Query("msgType"))
if err != nil {
return myCtx, err
}
if msgType < 1 || msgType > 2 {
return myCtx, bizerr.InvalidParameter
}
msgId, err := strconv.ParseUint(c.Query("msgId"), 10, 64)
if err != nil {
return myCtx, err
}
if msgId <= 0 {
return myCtx, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myCtx)
var resId common.MsgIdType
switch msgType {
case 1: // 邀请的消息im检查是否过期
cpRecord, err := cp_m.GetCpInviteById(model, msgId, userId)
if err != nil {
model.Log.Errorf("CheckCpImExpire userId:%d, msgType:%d, msgId:%d, err:%v", userId, msgType, msgId, err)
return myCtx, err
}
if cpRecord == nil || cpRecord.Id == 0 {
model.Log.Errorf("CheckCpImExpire userId:%d, msgType:%d, msgId:%d, err:%v", userId, msgType, msgId, bizerr.InvalidParameter)
return myCtx, bizerr.InvalidParameter
}
switch cpRecord.Status {
case cp_e.CpInvite:
if userId == cpRecord.UserId { // 发起人
resId = common.MSG_ID_WAITING_ACCEPTED // 等待对方接受
}
case cp_e.CpInviteAccept:
resId = common.MSG_ID_INVITATION_ACCEPTED // 已接受
case cp_e.CpInviteRefuse:
resId = common.MSG_ID_INVITATION_REFUSED // 已拒绝
case cp_e.CpInviteExpired:
resId = common.MSG_ID_ALREADY_EXPIRED
}
case 2: // 解除的消息im检查是否过期
cpCancel, err := cp_m.GetCpCancelById(model, msgId, userId)
if err != nil {
model.Log.Errorf("CheckCpImExpire userId:%d, msgType:%d, msgId:%d, err:%v", userId, msgType, msgId, err)
return myCtx, err
}
if cpCancel == nil || cpCancel.Id == 0 {
model.Log.Errorf("CheckCpImExpire userId:%d, msgType:%d, msgId:%d, err:%v", userId, msgType, msgId, bizerr.InvalidParameter)
return myCtx, bizerr.InvalidParameter
}
switch cpCancel.Status {
case cp_e.CpCancel:
if userId == cpCancel.UserId { // 发起人
resId = common.MSG_ID_WAITING_ACCEPTED // 等待对方接受
}
case cp_e.CpCancelRevoke:
resId = common.MSG_ID_HAS_BEEN_CANCELED // 已被取消
case cp_e.CpCancelAccept, cp_e.CpCancelAcceptAuto:
resId = common.MSG_ID_CP_UNBOUND // 已解绑
}
}
if resId > 0 {
return myCtx, myerr.ToLocal(msg.GetErrByLanguage(model, resId, lang, comerr.AlreadyExpired))
}
resp.ResponseOk(c, cp_cv.CheckCpImRes{})
return myCtx, nil
}
package cp_r
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"github.com/jinzhu/now"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"time"
)
// @Tags CP v2
// @Summary 排行榜
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageIndex query int true "偏移值 默认:1" default(1)
// @Param pageSize query int true "请求数量 默认:10" default(10)
// @Param queryType path string true "类型:day/week/month"
// @Success 200 {object} []cp_cv.CvCpRank
// @Router /v2/cp/rank/{queryType} [get]
func CpRank(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
pageReq := new(req.PageReqBase)
if err := c.ShouldBindQuery(pageReq); err != nil {
return myCtx, err
}
if pageReq.PageIndex == 0 {
pageReq.PageIndex = 1
}
queryType := c.Param("queryType")
if queryType != "day" && queryType != "week" && queryType != "month" {
return myCtx, bizerr.InvalidParameter
}
var beginDate, endDate string
switch queryType {
case "day":
beginDate, endDate = time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02")
case "week":
beginDate = now.BeginningOfWeek().Format("2006-01-02")
endDate = now.EndOfWeek().Format("2006-01-02")
case "month":
beginDate = now.BeginningOfMonth().Format("2006-01-02")
endDate = now.EndOfMonth().Format("2006-01-02")
}
offset, limit := (pageReq.PageIndex-1)*pageReq.PageSize, pageReq.PageSize
model := domain.CreateModelContext(myCtx)
ranks := cp_m.PageCpDayRank(model, beginDate, endDate, offset, limit)
var response []cp_cv.CvCpRank
var userIds []mysql.ID
var cpIds []mysql.ID
for _, rank := range ranks {
userIds = append(userIds, rank.UserId1)
userIds = append(userIds, rank.UserId2)
cpIds = append(cpIds, rank.CpId)
}
userBase, err := user_cv.GetUserBaseMap(userIds, userId)
if err != nil {
return myCtx, err
}
cpLevels := cp_m.MGetCpLevel(model, cpIds)
for i, rank := range ranks {
response = append(response, cp_cv.CvCpRank{
CpId: rank.CpId,
User1: userBase[rank.UserId1],
User2: userBase[rank.UserId2],
Score: rank.Score,
Ranking: fmt.Sprintf("%d", i+1+offset),
CpLevel: cp_cv.CvCpLevel{
Level: cpLevels[rank.CpId].Level,
//Points: cp_e.CpLevelPoints[cpLevel] + curPoints,
//EndPoints: nextPoints,
//RemainPoints: remainPoints,
//ExpireAtUnix: expireAtUnix,
},
})
}
resp.ResponsePageBaseOk(c, response, pageReq.PageIndex+1, len(ranks) >= pageReq.PageSize)
return myCtx, nil
}
// @Tags CP v2
// @Summary CP,Top3
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} cp_cv.CpTops
// @Router /v2/cp/top3 [get]
func CpTop3(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
var response = cp_cv.CpTops{
Day: make([]cp_cv.CvCpRank, 0),
Week: make([]cp_cv.CvCpRank, 0),
}
queryTypes := []string{"day", "week"}
for _, queryType := range queryTypes {
var beginDate, endDate string
switch queryType {
case "day":
beginDate, endDate = time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02")
case "week":
beginDate = now.BeginningOfWeek().Format("2006-01-02")
endDate = now.EndOfWeek().Format("2006-01-02")
}
offset, limit := 0, 3
model := domain.CreateModelContext(myCtx)
ranks := cp_m.PageCpDayRank(model, beginDate, endDate, offset, limit)
var userIds []mysql.ID
var cpIds []mysql.ID
for _, rank := range ranks {
userIds = append(userIds, rank.UserId1)
userIds = append(userIds, rank.UserId2)
cpIds = append(cpIds, rank.CpId)
}
userBase, err := user_cv.GetUserBaseMap(userIds, userId)
if err != nil {
return myCtx, err
}
cpLevels := cp_m.MGetCpLevel(model, cpIds)
for i, rank := range ranks {
if queryType == "day" {
response.Day = append(response.Day, cp_cv.CvCpRank{
CpId: rank.CpId,
User1: userBase[rank.UserId1],
User2: userBase[rank.UserId2],
Score: rank.Score,
Ranking: fmt.Sprintf("%d", i+1+offset),
CpLevel: cp_cv.CvCpLevel{
Level: cpLevels[rank.CpId].Level,
},
})
} else {
response.Week = append(response.Week, cp_cv.CvCpRank{
CpId: rank.CpId,
User1: userBase[rank.UserId1],
User2: userBase[rank.UserId2],
Score: rank.Score,
Ranking: fmt.Sprintf("%d", i+1+offset),
CpLevel: cp_cv.CvCpLevel{
Level: cpLevels[rank.CpId].Level,
},
})
}
}
}
resp.ResponseOk(c, response)
return myCtx, nil
}
// @Tags CP v2
// @Summary 我的cp
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param queryType path string true "类型:day/week/month"
// @Success 200 {object} cp_cv.CvCpRank
// @Router /v2/cp/my/{queryType} [get]
func CpMy(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
queryType := c.Param("queryType")
if queryType != "day" && queryType != "week" && queryType != "month" {
return myCtx, bizerr.InvalidParameter
}
var beginDate, endDate string
switch queryType {
case "day":
beginDate, endDate = time.Now().Format("2006-01-02"), time.Now().Format("2006-01-02")
case "week":
beginDate = now.BeginningOfWeek().Format("2006-01-02")
endDate = now.EndOfWeek().Format("2006-01-02")
case "month":
beginDate = now.BeginningOfMonth().Format("2006-01-02")
endDate = now.EndOfMonth().Format("2006-01-02")
}
model := domain.CreateModelContext(myCtx)
relation, exits := cp_m.GetCpRelation(model, userId)
var userIds []mysql.ID
var scores uint32
if exits {
// 保证一下自己是userId1
userIds = append(userIds, userId)
if relation.UserId1 == userId {
userIds = append(userIds, relation.UserId2)
} else {
userIds = append(userIds, relation.UserId1)
}
rank := cp_m.GetCpDayRank(model, beginDate, endDate, relation.Id)
scores = rank.Score
} else {
userIds = append(userIds, userId)
relation.UserId1 = userId
}
userBases, err := user_cv.GetUserBaseMap(userIds, userId)
if err != nil {
return myCtx, err
}
response := cp_cv.CvCpRank{
CpId: relation.Id,
Score: scores,
}
if relation.UserId1 > 0 {
response.User1 = userBases[relation.UserId1]
}
if relation.UserId2 > 0 {
response.User2 = userBases[relation.UserId2]
response.Ranking = "30+"
ranks := cp_m.PageCpDayRank(model, beginDate, endDate, 0, 30)
for i, rank := range ranks {
if relation.Id == rank.CpId {
response.Ranking = fmt.Sprintf("%d", i+1)
break
}
}
}
resp.ResponseOk(c, response)
return myCtx, nil
}
// @Tags CP v2
// @Summary 成就页
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageIndex query int true "偏移值 默认:1" default(1)
// @Param pageSize query int true "请求数量 默认:10" default(10)
// @Success 200 {object} []cp_cv.CvCpAchievement
// @Router /v2/cp/achievement [get]
func CpAchievement(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
model := domain.CreateModelContext(myCtx)
_, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
var response = make([]cp_cv.CvCpAchievement, 0)
TypeDescMap := map[cp_e.CpAchievement]uint{
cp_e.CpAchievementLevel: 280, //"等级分值最高",
cp_e.CpAchievementVisitors: 281, //"空间访问量最高",
cp_e.CpAchievementMonthRank: 282, //"月榜最高",
cp_e.CpAchievementWeekRank: 283, //"周榜最高",
cp_e.CpAchievementDayRank: 284, //"天榜最高",
}
achievements := cp_m.GetCpAchievements(model)
var userIds []uint64
var cpIds []uint64
for _, v := range achievements {
userIds = append(userIds, v.UserId1)
userIds = append(userIds, v.UserId2)
cpIds = append(cpIds, v.CpId)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myCtx, err
}
cpLevels := cp_m.MGetCpLevel(model, cpIds)
for _, a := range achievements {
response = append(response, cp_cv.CvCpAchievement{
CpId: a.CpId,
User1: user_cv.UserToTiny(users[a.UserId1]),
User2: user_cv.UserToTiny(users[a.UserId2]),
CpLevel: cpLevels[a.CpId].Level,
Type: a.Type,
TypeDesc: cp_m.GetTranslate(TypeDescMap[a.Type], lang),
Score: a.Score,
TimeUnix: a.UpdatedTime.Unix(),
})
}
resp.ResponsePageBaseOk(c, response, 0, false)
return myCtx, nil
}
package cp_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/event/cp_ev"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"time"
)
// @Tags CP v2
// @Summary cp空间
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param externalId query string true "查看用户的externalId"
// @Success 200 {object} cp_cv.CvSpace
// @Router /v2/cp/space [get]
func CpSpace(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
externalId := c.Query("externalId")
if len(externalId) <= 0 {
return myContext, bizerr.InvalidParameter
}
var model = domain.CreateModelContext(myContext)
userInfo, err := user_m.GetUser(model, userId)
if err != nil {
return myContext, err
}
targetUserInfo, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
var cpUserInfo *user_m.User
expireAtUnix, cpLevel := int64(0), cp_e.CpLevel0
visitTimes := int64(0)
settlementDate, cpDays, applyToUnbind := "", 0, false
nextPoints, curPoints := cp_e.CpLevelPoints[cp_e.CpLevel1], mysql.Num(0)
cpRelation, exists := cp_m.GetCpRelation(model, targetUserInfo.ID)
if exists {
level := cp_m.GetCpLevel(model, cpRelation.Id)
if level.ExpireAt.Before(time.Now()) {
level.ExpireAt = time.Now().AddDate(0, 1, 0)
}
cpLevel, curPoints = level.Level, level.Points
expireAtUnix, settlementDate = level.ExpireAt.Unix(), level.ExpireAt.Format("2006-01-02")
cpDays = int(time.Now().Sub(cpRelation.CreatedTime).Hours()/24) + 1
// cp 存在的时候,发布访问cp空间事件
if err := cp_ev.PublishCpSpaceVisit(model, &cp_ev.SpaceVisitEvent{
UserId: userId,
CpId: cpRelation.Id,
UserId1: cpRelation.UserId1,
UserId2: cpRelation.UserId2,
}); err != nil {
return myContext, err
}
visitTimes = cp_m.CountCpSpaceVisitors(model, cpRelation.Id)
cpUserId := cpRelation.UserId2
if cpUserId == userId {
cpUserId = cpRelation.UserId1
}
cpUserInfo, err = user_m.GetUser(model, cpUserId)
if err != nil {
return myContext, err
}
// 查看别人的cp空间
if userId != cpRelation.UserId1 && userId != cpRelation.UserId2 {
userInfo, err = user_m.GetUser(model, cpRelation.UserId1)
if err != nil {
return myContext, err
}
} else {
// 自己的空间
applyToUnbind = cp_m.GetApplyToUnbind(model, userId, cpUserId)
}
}
if cpLevel != cp_e.CpLevelMax {
nextPoints = cp_e.CpLevelPoints[cpLevel+1]
} else {
nextPoints = cp_e.CpLevelPoints[cp_e.CpLevelMax]
}
userPrivileges, err := cp_m.MGetUserSvipPrivilege(model, []uint64{userId})
if err != nil {
return myContext, err
}
allPrivilegeList := make([][]cp_cv.CvPrivilege, cp_e.CpLevelMax+1)
for level := cp_e.CpLevel0; level <= cp_e.CpLevelMax; level++ {
privilegeList := cp_cv.CopyCpLevelPrivilegeList(level, lang)
for i, v := range privilegeList {
if v.CanSwitch {
privilegeList[i].UserSwitch = userPrivileges[userId][v.Type]
}
}
allPrivilegeList[level] = privilegeList
}
// 返回值
response := cp_cv.CvSpace{
CpLevel: cp_cv.CvCpLevel{
Level: cpLevel,
Points: cp_e.CpLevelPoints[cpLevel] + curPoints,
StartPoints: cp_e.CpLevelPoints[cpLevel],
EndPoints: nextPoints,
ExpireAtUnix: expireAtUnix,
SettlementDate: settlementDate,
MaxLevel: cp_e.CpLevelMax,
},
ResLevelList: cp_cv.CvResLevelList,
PrivilegeList: allPrivilegeList,
}
response.CpInfo = cp_cv.CvCpInfo{
UserInfo: user_cv.UserToTiny(*userInfo),
CpDays: cpDays,
VisitTimes: visitTimes,
ApplyToUnbind: applyToUnbind,
}
if cpUserInfo != nil {
response.CpInfo.CpUserInfo = user_cv.UserToTiny(*cpUserInfo)
}
// 需要提醒的纪念日
if exists && (userId == cpRelation.UserId1 || userId == cpRelation.UserId2) {
anniversary := cp_m.GetUserTodayCpAnniversary(model, cpRelation.Id)
for _, a := range anniversary {
response.CpAnniversary = append(response.CpAnniversary, cp_cv.CvCpAnniversary{
Id: a.ID,
Content: a.Content,
Timestamp: a.Timestamp,
})
}
}
resp.ResponseOk(c, response)
return myContext, nil
}
type CpPrivilegeOpenCloseReq struct {
Type cp_e.CpPrivilege `form:"type" binding:"required"`
OpenClose mysql.OpenClose `form:"openClose" binding:"required"`
}
// @Tags CP v2
// @Summary cp特权开关
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param type formData int true "1.空间 2.横幅 3.等级勋章 4.证书 5.进场特效 6.头像头饰 7.动态资料卡 8.麦位特效"
// @Param openClose formData int true "1:open 2:close"
// @Success 200
// @Router /v2/cp/privilege/openClose [put]
func CpPrivilegeOpenClose(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var request CpPrivilegeOpenCloseReq
if err := c.ShouldBind(&request); err != nil {
return myCtx, err
}
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
var model = domain.CreateModelContext(myCtx)
if err := cp_m.OpenCLoseUserSvipPrivilege(model, userId, request.Type, request.OpenClose); err != nil {
return myCtx, err
}
resp.ResponseOk(c, "")
return myCtx, nil
}
......@@ -37,9 +37,6 @@ func wrapper(handler HandlerFunc) func(c *gin.Context) {
userId, _ := req.GetUserId(c)
switch h := err.(type) {
case *myerr.GameError:
myContext.Log.Warnf("request user err -> url:%v, method:%v, userId:%v, err :%+v\n", reqUri, method, userId, h.Error())
resp.GameResponseFail(c, h)
case *myerr.BusinessError:
myContext.Log.Warnf("request err -> url:%v, method:%v, userId:%v, err :%+v\n", reqUri, method, userId, h.GetErr())
resp.ResponseBusiness(c, h)
......
......@@ -102,6 +102,12 @@ func LoggerHandle(c *gin.Context) {
c.Set(mycontext.APP_VERSION, appVersion)
c.Set(mycontext.URL, reqUri)
c.Set(mycontext.METHOD, method)
lang := header.Get(mycontext.LANGUAGE)
c.Set(mycontext.LANGUAGE, lang)
carrier := header.Get(mycontext.CARRIER)
c.Set(mycontext.CARRIER, carrier)
timezone := header.Get(mycontext.TIMEZONE)
c.Set(mycontext.TIMEZONE, timezone)
userId, _ := req.GetUserId(c)
......
......@@ -11,6 +11,7 @@ import (
_ "hilo-user/docs"
"hilo-user/domain/model/msg_m"
"hilo-user/resp"
"hilo-user/route/cp_r"
"hilo-user/route/user_r"
)
......@@ -22,17 +23,42 @@ func InitRouter() *gin.Engine {
needLogin := r.Group("")
needLogin.Use(ExceptionHandle, LoggerHandle, JWTApiHandle)
v1 := needLogin.Group("/v1")
v2 := needLogin.Group("/v2")
user := v1.Group("/user")
{
user.GET("/nameplate", wrapper(user_r.UserNameplate))
user.GET("/bag/:resType", wrapper(user_r.UserBag))
}
cp := v2.Group("/cp")
{
cp.GET("/space", wrapper(cp_r.CpSpace))
cp.PUT("/privilege/openClose", wrapper(cp_r.CpPrivilegeOpenClose))
cp.GET("/rank/:queryType", wrapper(cp_r.CpRank))
cp.GET("/my/:queryType", wrapper(cp_r.CpMy))
cp.GET("/achievement", wrapper(cp_r.CpAchievement))
cp.GET("/top3", wrapper(cp_r.CpTop3))
cp.POST("/anniversary", wrapper(cp_r.PostAnniversary))
cp.PUT("/anniversary/:id", wrapper(cp_r.PutAnniversary))
cp.GET("/anniversary", wrapper(cp_r.PageAnniversary))
cp.DELETE("/anniversary/:id", wrapper(cp_r.DelAnniversary))
cp.GET("/relation/check", wrapper(cp_r.CheckUserCpRelation))
cp.POST("/relation", wrapper(cp_r.CpRelation))
cp.POST("/relation/invite/reply", wrapper(cp_r.ReplyCpInvite))
cp.POST("/relation/cancel/reply", wrapper(cp_r.ReplyCpCancel))
//cp.GET("/relation/detail", wrapper(cp_r.CpDetailPage))
cp.GET("/im/check", wrapper(cp_r.CheckCpImExpire))
}
inner := r.Group("/inner")
inner.Use(ExceptionHandle, LoggerHandle)
innerUser := inner.Group("/user")
{
innerUser.GET("/levels", wrapper(user_r.MGetUserLevels))
innerUser.GET("/bag/id", wrapper(user_r.GetUserBagId))
innerUser.GET("/cp", wrapper(user_r.GetUserCp))
innerUser.GET("/cpRelations", wrapper(user_r.MGetUserCpRelation))
innerUser.GET("/cp/pair", wrapper(user_r.GetUserCpPair))
}
// 道具相关
innerProp := inner.Group("/prop")
......
......@@ -4,6 +4,7 @@ import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/_const/enum/res_e"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/bag_m"
......@@ -44,7 +45,7 @@ func UserBag(c *gin.Context) (*mycontext.MyContext, error) {
}
for _, bagGift := range userBagGifts {
if gift, ok := allGifts[bagGift.ResId]; ok {
results = append(results, user_cv.UserBag{
info := user_cv.UserBag{
BagId: bagGift.ID,
ResType: res_e.ResUserBagGift,
ResId: gift.ID,
......@@ -55,7 +56,16 @@ func UserBag(c *gin.Context) (*mycontext.MyContext, error) {
SvgaUrl: gift.SvagUrl,
Count: bagGift.Count,
RemainDays: int(bagGift.EndTime.Sub(time.Now()).Hours() / 24),
})
}
if gift.ID == cp_e.CpConfessionGiftId { // 如果是cp告白礼物
info.TextStyleList = make([]*user_cv.TextStyle, 0, 2)
info.TextStyleList = append(info.TextStyleList,
&user_cv.TextStyle{TextColor: "#ce0083", TextSize: 20, TextKey: "sender_name"},
&user_cv.TextStyle{TextColor: "#ce0083", TextSize: 20, TextKey: "receiver_name"},
)
}
results = append(results, info)
}
}
default:
......
......@@ -5,8 +5,11 @@ import (
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/bag_m"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
......@@ -90,3 +93,166 @@ func GetUserBagId(c *gin.Context) (*mycontext.MyContext, error) {
})
return myCtx, nil
}
type GetUserCpReq struct {
Id mysql.ID `form:"id" binding:"required"`
Language string `form:"language"`
}
// @Tags 用户-内部
// @Summary 获取用户cp
// @Param id query int true "用户id"
// @Param language query string true "语言"
// @Success 200 {object} cp_cv.CvCp
// @Router /inner/user/cp [get]
func GetUserCp(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myContext)
var req GetUserCpReq
if err := c.ShouldBindQuery(&req); err != nil {
return myContext, err
}
userId := req.Id
var response cp_cv.CvCp
cpLevel := cp_e.CpLevel0
cpRelation, exists := cp_m.GetCpRelation(model, userId)
if !exists {
resp.ResponseOk(c, response)
return myContext, nil
}
var myPrivilegeList []cp_cv.CvPrivilege
level := cp_m.GetCpLevel(model, cpRelation.Id)
if level.ExpireAt.Before(time.Now()) {
level.ExpireAt = time.Now().AddDate(0, 1, 0)
}
cpLevel = level.Level
cpUserId := cpRelation.UserId2
if cpUserId == userId {
cpUserId = cpRelation.UserId1
}
userPrivileges, err := cp_m.MGetUserSvipPrivilege(model, []uint64{userId})
if err != nil {
return myContext, err
}
privilegeList := cp_cv.CopyCpLevelPrivilegeList(level.Level, "en")
for i, v := range privilegeList {
if v.CanSwitch {
privilegeList[i].UserSwitch = userPrivileges[userId][v.Type]
}
}
// 我的特权,有开关并且打开才返回
for i, v := range privilegeList {
if !v.CanSwitch {
myPrivilegeList = append(myPrivilegeList, privilegeList[i])
} else if v.UserSwitch {
myPrivilegeList = append(myPrivilegeList, privilegeList[i])
}
}
userBases, err := user_cv.GetUserBaseMap([]uint64{cpUserId}, userId)
if err != nil {
return myContext, err
}
// 返回值
title := ""
if msgId, ok := cp_e.CpLevelTitle[level.Level]; ok {
title = cp_cv.GetTranslate(msgId, req.Language)
}
response = cp_cv.CvCp{
CpUserInfo: userBases[cpUserId],
CpLevel: cp_cv.CvCpLevel{
Level: cpLevel,
Points: cp_e.CpLevelPoints[cpLevel] + level.Points,
Title: title,
},
MyPrivilegeList: myPrivilegeList,
CpDays: int(time.Now().Sub(cpRelation.CreatedTime).Hours()/24) + 1,
CreatedUnix: cpRelation.CreatedTime.Unix(),
}
resp.ResponseOk(c, response)
return myContext, nil
}
type MGetUserCpRelationReq struct {
Ids []mysql.ID `form:"ids" binding:"required"`
}
// @Tags 用户-内部
// @Summary 批量获取用户cp关系
// @Param ids query int true "用户ids"
// @Success 200 {object} map[uint64]cp_cv.CvCpRelation
// @Router /inner/user/cpRelations [get]
func MGetUserCpRelation(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myContext)
var req MGetUserCpRelationReq
if err := c.ShouldBindQuery(&req); err != nil {
return myContext, err
}
cpRelations := cp_m.MGetCpRelation(model, req.Ids)
var m = make(map[uint64]cp_m.CpRelation)
var userIds []uint64
for i, v := range cpRelations {
m[v.UserId1] = cpRelations[i]
m[v.UserId2] = cpRelations[i]
userIds = append(userIds, v.UserId1)
userIds = append(userIds, v.UserId2)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myContext, err
}
var response = make(map[uint64]cp_cv.CvCpRelation)
for _, uid := range req.Ids {
if cpRelation, ok := m[uid]; ok {
cpUserId := cpRelation.UserId2
if cpUserId == uid {
cpUserId = cpRelation.UserId1
}
response[uid] = cp_cv.CvCpRelation{
CpId: cpRelation.Id,
UserId: uid,
CpUserId: cpUserId,
CpUserAvatar: users[cpUserId].Avatar,
}
}
}
resp.ResponseOk(c, response)
return myContext, nil
}
type GetUserCpPairReq struct {
Ids []mysql.ID `form:"ids" binding:"required"`
}
// @Tags 用户-内部
// @Summary 给出指定uids下的cp对
// @Param ids query string true "用户id,如:ids=1&ids=2&ids=3"
// @Success 200 {object} [][]uint64
// @Router /inner/user/cp/pair [get]
func GetUserCpPair(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myContext)
var req GetUserCpPairReq
if err := c.ShouldBindQuery(&req); err != nil {
return myContext, err
}
userIds := req.Ids
m := make(map[mysql.ID]bool)
for _, uid := range userIds {
m[uid] = true
}
pairs := cp_m.MGetCpRelation(model, userIds)
var cpIds []mysql.ID
for _, pair := range pairs {
cpIds = append(cpIds, pair.Id)
}
levels := cp_m.MGetCpLevel(model, cpIds)
var response [][3]uint64
for _, pair := range pairs {
if m[pair.UserId1] && m[pair.UserId2] {
response = append(response, [3]mysql.ID{pair.UserId1, pair.UserId2, uint64(levels[pair.Id].Level)})
}
}
resp.ResponseOk(c, response)
return myContext, nil
}
MODE=local
package test
import (
"git.hilo.cn/hilo-common/domain"
"hilo-user/domain/model/cp_m"
"testing"
)
func TestInitCpAnniversary(t *testing.T) {
err := cp_m.InitCpAnniversary(domain.CreateModelNil(), cp_m.CpRelation{
Id: 1,
UserId1: 7642,
UserId2: 4549,
}, "ar")
println(err)
}
[DATABASE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo
[DATABASECODE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo_code
[REDIS]
REDIS_HOST=47.244.34.27:6379
REDIS_PASSWORD=8QZ9JD1zLvPR3yHf
[JWT]
SECRET=hilo1632
ISSUER_API=hiloApi
ISSUER_Mgr=hiloMgr
EXPIRE=240h
[GAMEJWT]
SECRET=hilo1632
ISSUER_CLIENT=hiloClient
ISSUER_SERVER=hiloServer
EXPIRE=240h
[APP]
MASTER=false
BIZ_SECRET=biz
WEB_SECRET=webHilo1258
OPERATION_SECRET=operation1258236
SUPERUSER=2701,2831
OFFICIAL_STAFF=2701,2831
OFFICIAL_GROUP=@TGS#3NC2ATRHS,@TGS#33W3KNLHK
MINIMAL_VERSION_ANDROID=212
MINIMAL_VERSION_IOS=100
MODERATE=AWS
[OSS]
OSS_ACCESS_KEY_ID=LTAIxdazV2pCuV3T
OSS_ACCESS_KEY_SECRET=zuAnreAXQ6vlAKnvvmolFLfb1N5w5S
OSS_ROLE_ARN=acs:ram::1509841556585969:role/aliyunosstokengeneratorrole
OSS_END_POINT=http://oss-accelerate.aliyuncs.com
OSS_BUCKET=starvoice
OSS_CDN=https://oss.chathot.me/
OSS_EXPIRED_TIME=3600
OSS_STS_POINT=me-east-1
OSS_STS=sts-faceline-demo
OSS_STS_AES=484194d4d0f968a7
[AWS]
AWS_BUCKET=starchat
AWS_CDN=https://image.whoisamy.shop/
AWS_DIR=hilo/
CONFIDENCE=80
[RONGYUN]
RONG_CLOUD_APP_KEY=pvxdm17jpe9tr
RONG_CLOUD_APP_SECRET=rI4giiKWaBS4
RONG_CLOUD_URL=https://api-sg01.ronghub.com
[TENCENTYUN]
TENCENTYUN_APP_ID=1400548270
TENCENTYUN_KEY=321bd60f73096b059c7350f1cd97d51028850b34fa58c5c0d26bb4a19e783de8
TX_OVERSEA_APP_ID=40000066
TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c
[EMAS]
REGION_ID=cn-hangzhou
ACCESS_KEY_ID=LTAI4FhNPzxdzD4w6bHirL9Z
ACCESS_KEY_SECRET=OQvUJpXDrjGi3g1F2aHiAIFWIvLdbP
ANDROID_APP_KEY=30250713
ANDROID_APP_SECRET=cae7b9a9d3e54577d2c3b60bf6d23047
IOS_APP_KEY=30240346
IOS_APP_SECRET=57f33ab9ca6a957a8c659f2b0b6d1205
APNS=DEV
[AGORA]
APP_ID=fc3e087f701b4f788099e1924c3cc7b0
APP_CERTIFICATE=ff29c100a613433db82324e8411eabc8
CUSTOMER_KEY=6b132c0ff7164560a2bc53fda06ea85a
CUSTOMER_SECRET=eedad2cd16d24834990d5450ace9f1ce
CALLBACK_SECRET=n_ZizS_N8
[CHECKOUT]
AUTHORIZATION=sk_test_9b5e771c-5a3f-4a8d-a4da-31b19bd43d83
URL=https://api.sandbox.checkout.com/hosted-payments
H5=http://test.chathot.me/action/hiloHtml/22_05_30_recharge/topup.html
HILO_SECRET_KEY=sk_test_dfbaa3b6-135d-4376-9996-2089b7d8a086
[MATCH]
MATCH_FREE_TIME=60
MATCH_FREE_TIME_VIP=300
MATCH_ADD_TIME_FREE=90
MATCH_AGORA_TIME=30
MATCH_CYCLE=8
MATCH_USER_EXPIRES=480
MATCH_SUCCESS_WAIT_DURATION=10
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC=12
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC=15
[ONLINE]
ONLINE_CYCLE=600
ONLINE_USER_EXPIRES=259200
[VIDEO]
VIDEO_DAILY_FREE_NUM=20
VIDEO_FREE_TIME=60
VIDEO_FREE_TIME_VIP=300
VIDEO_ADD_TIME_FREE=60
VIDEO_AGORA_TIME=30
VIDEO_MINUTE_NORMAL=1000
VIDEO_MINUTE_UNION=2000
[SESSION]
SESSION_DAILY_FREE_NUM=50
[BEAN]
DIAMOND_BEAN_RATE=90
[H5]
USER_LEVEL=http://test.chathot.me/action/activityhtml/hiloUserLevel/index.html
GROUP_SUPPORT=http://test.chathot.me/action/activityhtml/21_12_06/page.html
LUCKY_WHEEL=https://h5.whoisamy.shop/action/activityhtml/21_12_30/page.html
NOBLE_BUY_IOS=https://h5.whoisamy.shop/action/hiloHtml/lxt_h5/page.html
[GROUPIM]
MSG_SORT_EXPIRE=43200
MSG_SORT_SNAP=300
[GRADE]
CHARM_SPEED_VIP=15
ACTITY_SPEED_VIP=15
WEALTH_SPEED_VIP=15
[LIKE]
I_LIKE_NUM=30
I_LIKE_NUM_VIP=100
I_LIKE_NUM_NOBLE=1000
[APPLEPAY]
PASSWORD=38702750a05c4cb09c9d6ca646835634
[REGISTER]
IMEI_TOTAL=3
IMEI_OAUTH=2
ACCOUNT_IP=100
ACCOUNT_IP_DURATION=21600
[BANNER]
GIFT_BANNER_LEVEL1=100
GIFT_BANNER_LEVEL2=2000
GIFT_BANNER_LEVEL3=5000
[DIAMOND]
DAILY_LOGIN_IMEI_LIMIT=200
DAILY_LOGIN_IP_LIMIT=5
PRIVATE_GIFT_RETURN=1440
NEW_USER_INVITE_AWARD=5000
[LUCKY_WHEEL]
MINIMAL_PARTICIPANT=2
WAIT_TIMELONG=10
WINNER_DIAMOND_BANNER=100
[GROUP_CUSTOM_THEME]
PIC_LIMIT=5
DAY=10
[GIFT]
WALL_DIAMOND=10
[DAILY]
LOGIN_COMMON=5
LOGIN_VIP=300
[DAILY]
LOGIN_COMMON=5
LOGIN_VIP=300
[FRUIT_TYCOON]
POOL_RATIO=20
WATERMELON_RATIO=70
[ACTIVITY]
COUNTRY_STAR_POOL_RATIO=20
COUNTRY_STAR_ORDINARY_RATIO=20
[PAYER_MAX]
URL=https://pay-gate-uat.payermax.com/aggregate-pay-gate/api/gateway
KEY=d50d149a883b8bb6
MERCHANT_ID=SP11018326
BIZ_TYPE=CUSTOMIZE
VERSION=2.3
FRONT_CALLBACK_URL=https://www.hiloconn.com
SHOW_RESULT=1
EXPIRE_TIME=1800
LANGUAGE=en
[SUD]
API_LIST=https://sim-asc.sudden.ltd
[URL]
BIZ_HTTP=https://test.apiv1.faceline.live
\ No newline at end of file