...
 
Commits (99)
swag: swag:
swag init swag init
proto:
protoc --go_out=./ --go-grpc_out=. ./protocol/*.proto
\ No newline at end of file
package country_e
import "git.hilo.cn/hilo-common/resource/mysql"
// 国家角色
type CountryMgrRole mysql.Type
const (
// 国家管理员
CountryMgrManager CountryMgrRole = 1
// 国家助理
CountryMgrAssistant CountryMgrRole = 2
)
// 角色权限
type ManagerPrivilegeItem mysql.Type
const (
// 重置用户头像
ManagerPrivilegeItemResetAvatar ManagerPrivilegeItem = 1
// 重置群组头像
ManagerPrivilegeItemResetFaceUrl ManagerPrivilegeItem = 2
// 删除广播
ManagerPrivilegeItemDeleteGlobalBroadcast ManagerPrivilegeItem = 3
)
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 // 头像类型
AnniversaryItemTypeBirthday1 AnniversaryItemType = 2 // user1的生日
AnniversaryItemTypeBirthday2 AnniversaryItemType = 3 // user2的生日
AnniversaryItemTypeAnniversary AnniversaryItemType = 4 // 纪念日
)
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
CpPrivilegeIcon = map[CpPrivilege]map[CpLevel]string{
CpPrivilegeSpace: {CpLevel0: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png", CpLevel1: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png", CpLevel2: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png", CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_space.png"},
CpPrivilegeBanner: {CpLevel1: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_banner1.png", CpLevel2: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_banner2.png", CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_banner3.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_banner4.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_banner5.png"},
CpPrivilegeMedal: {CpLevel1: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_medal1.png", CpLevel2: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_medal2.png", CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_medal3.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_medal4.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_medal5.png"},
CpPrivilegeCert: {CpLevel0: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert0.png", CpLevel1: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert1.png", CpLevel2: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert2.png", CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert3.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert4.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_cert5.png"},
CpPrivilegeRoomEffect: {CpLevel2: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_enter2.png", CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_enter3.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_enter4.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_enter5.png"},
CpPrivilegeHeadwear: {CpLevel3: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_headwear.png", CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_headwear.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_headwear.png"},
CpPrivilegeActiveProfile: {CpLevel4: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_profile.png", CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_profile.png"},
CpPrivilegeMicEffect: {CpLevel5: "https://image.whoisamy.shop/hilo/resource/cp/cp_p_mic.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 diamond_e
import "hilo-user/resource/mysql"
type StatusAccount = mysql.Type
const (
Normal StatusAccount = 1
//冻结,只是限制减少,不限制增加
Frozen StatusAccount = 2
)
type OperateType = mysql.Type
const (
//注册
/* REGISTER OperateType = 1
//建立融云会话
SessionPay OperateType = 2
//购买钻石
BuyDiamond OperateType = 3
//发送礼物
SendGift OperateType = 4
//接受礼物
ReceiveGift OperateType = 5
//匹配条件
MatchCondition OperateType = 6*/
SendGift OperateType = 1 //发送礼物
MatchCondition OperateType = 2 //匹配条件
SessionPay OperateType = 3 //建立融云会话
BuyDiamond OperateType = 4 //购买钻石
ReceiveGift OperateType = 5 //接受礼物
REGISTER OperateType = 6 //注册
MgrSend OperateType = 8 //平台赠送
VideoCost OperateType = 9 //1对1视频花费
MgrReduce OperateType = 10 //平台扣除
ActivityBillboard OperateType = 11 //活动榜单奖励
ExchangeBean OperateType = 12 //钻石兑换豆子
ActivityGroupBillboard OperateType = 13 //活动榜单奖励
DailyInAppVip OperateType = 14 //每日登陆领取钻石(VIP)
GroupIMMass OperateType = 15 //群中IM群发
DailyInAppCommon OperateType = 16 //每日登陆领取钻石(普通用户)
GroupSupportAdmin OperateType = 17 //群组支持(利益分配者)
GroupSupportMgr OperateType = 18 //群主支持(助手)
MgrBillDiamond OperateType = 19 //管理人单据送钻石
Headwear OperateType = 20 //送头饰扣费
Property OperateType = 21 //送坐骑扣费
LuckyWheelJoin OperateType = 22 //参与转盘扣费
LuckyWheelCancel OperateType = 23 //转盘取消
LuckyWheelWin OperateType = 24 //转盘奖励
LuckWheelGroupOwer OperateType = 25 //转盘群主抽成
DealerTransfer OperateType = 26 //币商转账
GroupCustomTheme OperateType = 27 //购买群组自定义主题
RocketAward OperateType = 28 //火箭奖励
LuckyboxBuy OperateType = 29 //幸运盒子购买
LuckyboxAward OperateType = 30 //幸运盒子奖励
PrivateGift OperateType = 31 // 私聊送礼物
PrivateGiftReturn OperateType = 32 // 私聊送礼物退款
ActivityTriggerAward OperateType = 33 //活动触发奖励
VideoTradeUnionGift OperateType = 34 // 视频送礼物
VideoTradeUnionGiftReturn OperateType = 35 // 视频送礼物退款
GlobalBroadcast OperateType = 36 //全球发布消息
TaskAward OperateType = 37 //任务奖励
FruitMachineAward OperateType = 38 // 水果机奖励
FruitMachineBet OperateType = 39 // 水果机投注
Noble OperateType = 40 //购买/赠送贵族
FruitTycoonAward OperateType = 41 // 水果大亨奖励
Checkout OperateType = 42 //checkout购买
LuckyboxCycle OperateType = 43 //幸运盒子回收奖励
ActivityRechargeFirst OperateType = 44 //首次充值奖励
NewUserInvite OperateType = 45 // 新用户奖励活动
GeneralActivity OperateType = 46 // 一般性活动奖励
PowerSupportOwner OperateType = 47 // 势力支持(势力主)
PowerSupportAssistant OperateType = 48 // 势力支持(助手)
VideoMinute OperateType = 49 //1对1视频(分钟扣费)
MatchMinute OperateType = 50 //匹配视频(第一分钟扣费)
VideoMinuteBack OperateType = 51 //1对1视频(分钟扣费,返回)
VideoMinuteTotal OperateType = 52 //1对1视频(分钟扣费,返回)
GroupActivity OperateType = 53 //创建群组活动
GroupActivityReward OperateType = 54 //群组活动奖励
PayerMax OperateType = 55 //payerMax/茄子支付购买
BuyPinkDiamond OperateType = 56 //购买粉钻
VideoCostPink OperateType = 57 //1对1视频送礼(粉钻)
MatchMinutePink OperateType = 58 //匹配视频(第一分钟扣费)(粉钻)
VideoMinuteTotalPink OperateType = 59 //1对1视频(分钟扣费,返回)(粉钻)
SendPinkGift OperateType = 60 //送粉钻礼物 ---占位---暂不开放 数据库配置表中暂未配置
MatchMinuteGiftPink OperateType = 61 //匹配视频送礼(粉钻)
MatchMinuteGiftPinkTime OperateType = 62 //匹配视频加时送礼(粉钻)
JoinGroupCost OperateType = 63 //加入群组扣费
JoinGroupAdd OperateType = 64 //加入群组,群主得黄钻
GameJoin OperateType = 65 //加入游戏扣费
GameAward OperateType = 66 //游戏结算奖励
GameRefund OperateType = 67 //游戏退费
)
const (
DiamondYellow mysql.Type = 1
DiamondPink mysql.Type = 2
)
package user_e
type ReportType string
type GameType int
type GameOpt int
type GameStatus uint8
type GamerStatus uint8
type GamerPlayerStatus uint8
type GameMode = int
const (
ReportTypeGameStart ReportType = "user_start" // 战斗开始通知
ReportTypeGameSettle ReportType = "user_settle" // 战斗结算通知
GameAutoMatchYes = 1 // 游戏自动匹配
GameAutoMatchNo = 0 // 游戏非自动匹配
GameTypeLudo GameType = 1 // ludo
GameTypeUno GameType = 2 // uno
GameModeQuick GameMode = 0
GameModeClassic GameMode = 1
GameOptCreate GameOpt = 0 // 创建游戏
GameOptJoin GameOpt = 1 // 加入游戏,自动准备
GameOptExit GameOpt = 2 // 退出游戏
GameOptClose GameOpt = 3 // 创建者关闭游戏
//GameOptReady GameOpt = 2 // 准备游戏
//GameOptCancelReady GameOpt = 3 // 取消准备游戏
GameStatusNoStart GameStatus = 0 // 未开始
GameStatusGaming GameStatus = 1 // 游戏中
GameStatusEnd GameStatus = 2 // 游戏结束
GamerStatusUnready GamerStatus = 0 // 未开始
GamerStatusGaming GamerStatus = 1 // 游戏中
GamerStatusEnd GamerStatus = 2 // 游戏结束
GamerExit GamerStatus = 3 // 自己退出游戏
GamerClose GamerStatus = 4 // 创建者关闭游戏
//GamerStatusReady GamerStatus = 1 // 准备
//GamerExit GamerStatus = 4 // 自己退出游戏
MgIdLudo = "1468180338417074177"
MgIdUno = "1472142559912517633"
)
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 // 国家之星活动入口
)
package groupPower_e package groupPower_e
import "hilo-user/resource/mysql" import "git.hilo.cn/hilo-common/resource/mysql"
// 国家势力状态 //国家势力状态
type GroupPowerStatus = mysql.Type type GroupPowerStatus = mysql.Type
const ( const (
...@@ -14,17 +14,19 @@ const ( ...@@ -14,17 +14,19 @@ const (
GroupPowerDissolve GroupPowerStatus = 3 GroupPowerDissolve GroupPowerStatus = 3
) )
// 国家势力用户角色 //国家势力用户角色
type GroupPowerUserRole = mysql.Type type GroupPowerUserRole = mysql.Type
const ( const (
//普通用户 // 普通用户
GroupPowerUserRoleUser GroupPowerUserRole = 1 GroupPowerUserRoleUser GroupPowerUserRole = 1
//势力主 // 势力主
GroupPowerUserRoleMgr GroupPowerUserRole = 2 GroupPowerUserRoleMgr GroupPowerUserRole = 2
// 管理员
GroupPowerUserRoleAdmin GroupPowerUserRole = 3
) )
// 国家势力日志操作类型 //国家势力日志操作类型
type GroupPowerUserLogType = mysql.Type type GroupPowerUserLogType = mysql.Type
const ( const (
......
package group_e package group_e
import "hilo-user/resource/mysql" import "git.hilo.cn/hilo-common/resource/mysql"
type MsgStatusGroupUser = mysql.Type
const (
//正常: 灰点+震动
NormalMsgStatusGroupUser MsgStatusGroupUser = 0
//静音:灰点
MuteMsgStatusGroupUser MsgStatusGroupUser = 1
//免打扰:什么也没有
DoNotDisturbMsgStatusGroupUser MsgStatusGroupUser = 2
OverseaRoom = 1
LocalRoom = 2
)
// 公屏消息
type TypePublicScreenMsg = mysql.Type
const (
UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组
UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间
UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户
RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色
RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色
ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用
RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果
GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物
GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5
JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息
RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息
LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖
FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖
EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间
)
// 信令消息(不显示公屏工,不记入消息历史,不影响未读数) // 信令消息(不显示公屏工,不记入消息历史,不影响未读数)
type TypeSignalMsg = mysql.Type type TypeSignalMsg = mysql.Type
...@@ -21,7 +55,7 @@ const ( ...@@ -21,7 +55,7 @@ const (
GroupKickOut TypeSignalMsg = 13 //保留 GroupKickOut TypeSignalMsg = 13 //保留
GroupSocketMicOutSignal TypeSignalMsg = 14 //保留 GroupSocketMicOutSignal TypeSignalMsg = 14 //保留
GroupInviteMicInSignal TypeSignalMsg = 15 //邀请上麦保留 GroupInviteMicInSignal TypeSignalMsg = 15 //邀请上麦保留
GroupInSignal TypeSignalMsg = 16 //进入房间 GroupInSignal TypeSignalMsg = 16 //进入房间,进房特效
GroupMicEmoji TypeSignalMsg = 17 //麦上表情 GroupMicEmoji TypeSignalMsg = 17 //麦上表情
GroupLuckyWheel TypeSignalMsg = 18 //转盘的通知信令 GroupLuckyWheel TypeSignalMsg = 18 //转盘的通知信令
GroupOutSignal TypeSignalMsg = 19 //离开房间 GroupOutSignal TypeSignalMsg = 19 //离开房间
...@@ -30,14 +64,11 @@ const ( ...@@ -30,14 +64,11 @@ const (
GroupMicChange TypeSignalMsg = 22 //房间麦位上的变量 GroupMicChange TypeSignalMsg = 22 //房间麦位上的变量
GroupMemberInvite TypeSignalMsg = 23 //房间-邀请用户成为会员 GroupMemberInvite TypeSignalMsg = 23 //房间-邀请用户成为会员
GroupRoleChange TypeSignalMsg = 24 //房间-用户群组身份变化 GroupRoleChange TypeSignalMsg = 24 //房间-用户群组身份变化
GroupClearScreen TypeSignalMsg = 25 //房间-清理公屏
GroupGameInfoLudo TypeSignalMsg = 200 // 房间-游戏信息-ludo GroupRoomGiftSignal TypeSignalMsg = 26 //全房间送礼物
GroupGameSettleLudo TypeSignalMsg = 201 // 房间-游戏结算信息-ludo
GroupGameInfoUno TypeSignalMsg = 202 // 房间-游戏信息-uno
GroupGameSettleUno TypeSignalMsg = 203 // 房间-游戏结算信息-uno
) )
// 群组麦位数量类型 //群组麦位数量类型
type GroupMicNumType = mysql.Type type GroupMicNumType = mysql.Type
const ( const (
...@@ -64,27 +95,7 @@ const ( ...@@ -64,27 +95,7 @@ const (
//10个麦位 //10个麦位
TenMicNumType GroupMicNumType = 2 TenMicNumType GroupMicNumType = 2
// //
)
// 公屏消息
type TypePublicScreenMsg = mysql.Type
const (
UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组
UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间
UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户
RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色
RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色
ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用
RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果
GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物
GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5
JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息
RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息
LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖
FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖
EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间
GameLudoPubMsg TypePublicScreenMsg = 101 // Ludo游戏公屏 SUPPORT_LEVEL_BOUNDARY_HOUR = 0
GameUnoPubMsg TypePublicScreenMsg = 102 // uno游戏公屏 SUPPORT_LEVEL_PERIOD_DAY = 7
) )
package headwear_e
import "git.hilo.cn/hilo-common/resource/mysql"
type UserHeadwearUsing = mysql.Type
const (
YesUsing UserHeadwearUsing = 1
NoUsing UserHeadwearUsing = 0
)
type UserHeadwearLogOrginType = mysql.Type
const (
Mgr UserHeadwearLogOrginType = 1
//购买,或者别人购买
Send UserHeadwearLogOrginType = 2
Activity UserHeadwearLogOrginType = 3
Rocket UserHeadwearLogOrginType = 4
//活动阀值自动触发奖励
ActivityTrigger UserHeadwearLogOrginType = 5
//首次充值奖励
ActivityRechargeFirst UserHeadwearLogOrginType = 6
//别人赠送
Give UserHeadwearLogOrginType = 7
GeneralActivity UserHeadwearLogOrginType = 8
)
type UserHeadwearLogType mysql.Type
const (
AddSecond UserHeadwearLogType = 1
UpdateEndTime UserHeadwearLogType = 2
Del UserHeadwearLogType = 3
)
package match_e
import "hilo-user/resource/mysql"
/****************************/
type MatchDetailDataChange mysql.NumAll
const (
AddDataChange MatchDetailDataChange = 1
ReduceDataChange MatchDetailDataChange = 2
ZeroDataChange MatchDetailDataChange = 0
)
/******元素分数***************/
/*type EnumCountType mysql.Type
const (
PriorityEnumCountType EnumCountType = 1
ExcellentEnumCountType EnumCountType = 2
RelationEnumCountType EnumCountType = 3
)*/
/*const (
//接收到礼物的数量
ReceiveGiftNumCountType EnumCountType = 1
//接收到礼物的频率
ReceiveGiftFCountType EnumCountType = 2
//被举报
BeReportCountType EnumCountType = 3
//被拉黑
BeBlackCountType EnumCountType = 4
//支付次数
PayCountType EnumCountType = 5
//被喜欢的次数
LikeMeType EnumCountType = 6
//新用户
NewUserType EnumCountType = 7
//连续被拒
AgainRefuse EnumCountType = 8
//每天新登陆用户
DailyUserType EnumCountType = 9
//活跃等级
ActiveGrade EnumCountType = 10
//连续同性
AgainSameSex EnumCountType = 11
//匹配推送次数
MatchSuccessNum EnumCountType = 12
//匹配推送接受次数
MatchConfirmNum EnumCountType = 13
//接通率
MatchConfirmRate EnumCountType = 14
//免费加时
MatchFreeTimeNum EnumCountType = 15
//礼物加时
MatchGiftTimeNum EnumCountType = 16
//加时率
MatchAddTimeRate EnumCountType = 17
//工会成员
TradeUnion EnumCountType = 18
//匹配拒绝
RelationMatchRefuse EnumCountType = 19
//匹配用户
RelationMatchUser EnumCountType = 20
)*/
// 优先度排序
type PriorityUserFormOriginType mysql.Type
const (
//钻石余额
PriorityDiamond PriorityUserFormOriginType = 1
//首充
PriorityFirstCharge PriorityUserFormOriginType = 2
//财富等级
PriorityWealthGrade PriorityUserFormOriginType = 3
//被举报
PriorityBeReport PriorityUserFormOriginType = 4
//被拉黑
PriorityBeBlack PriorityUserFormOriginType = 5
//近期充值
PriorityRecentlyPay PriorityUserFormOriginType = 6
//新用户
PriorityNewUserType PriorityUserFormOriginType = 7
//连续被拒
PriorityAgainRefuse PriorityUserFormOriginType = 8
//每天新登陆用户
PriorityDailyUserType PriorityUserFormOriginType = 9
//活跃等级
PriorityActiveGrade PriorityUserFormOriginType = 10
//工会
PriorityTradeUnion PriorityUserFormOriginType = 11
//多次匹配到同性
PriorityAgainSameSex PriorityUserFormOriginType = 12
)
var PriorityMap = map[PriorityUserFormOriginType]string{
PriorityDiamond: "钻石余额",
PriorityFirstCharge: "首充",
PriorityWealthGrade: "财富等级",
PriorityBeReport: "被举报",
PriorityBeBlack: "被拉黑",
PriorityRecentlyPay: "近期充值",
PriorityNewUserType: "新用户",
PriorityAgainRefuse: "连续被拒",
PriorityDailyUserType: "每天新登陆用户",
PriorityActiveGrade: "活跃等级",
PriorityTradeUnion: "工会",
PriorityAgainSameSex: "连续同性",
}
// 质量排序
type ExcellentUserFormOriginType mysql.Type
const (
//被喜欢的次数
ExcellentLikeMe ExcellentUserFormOriginType = 1
//接收礼物数量
ExcellentReceiveGiftNumChange ExcellentUserFormOriginType = 2
//接收礼物次数
ExcellentReceiveGiftFChange ExcellentUserFormOriginType = 3
//被投诉次数
ExcellentBeReport ExcellentUserFormOriginType = 4
//被拉黑的次数
ExcellentBeBlack ExcellentUserFormOriginType = 5
//魅力等级
ExcellentCharmGrade ExcellentUserFormOriginType = 6
//被付费建立融云会话
ExcellentSessionCreate ExcellentUserFormOriginType = 7
//接通率
ExcellentMatchConfirmRate ExcellentUserFormOriginType = 8
//加时率(视频通话加时次数(免费加时成功 + 礼物加时成功)/视频通话次数(匹配成功的次数))
ExcellentAddTimeRate ExcellentUserFormOriginType = 9
//工会成员
ExcellentTradeUnion ExcellentUserFormOriginType = 10
//匹配成功次数
ExcellentMatchSuccessNum ExcellentUserFormOriginType = 11
//匹配确认次数
ExcellentMatchConfirmNum ExcellentUserFormOriginType = 12
//匹配免费加时的次数
ExcellentMatchFreeTimeNum ExcellentUserFormOriginType = 13
//匹配礼物加时次数
ExcellentMatchGiftTimeNum ExcellentUserFormOriginType = 14
)
var ExcellentMap = map[ExcellentUserFormOriginType]string{
ExcellentLikeMe: "喜欢我",
ExcellentReceiveGiftNumChange: "接收礼物数量",
ExcellentReceiveGiftFChange: "接收礼物次数",
ExcellentBeReport: "被投诉次数",
ExcellentBeBlack: "被拉黑次数",
ExcellentCharmGrade: "魅力等级",
ExcellentSessionCreate: "被付费建立融云会话",
ExcellentMatchConfirmRate: "接通率",
ExcellentAddTimeRate: "加时率",
ExcellentTradeUnion: "工会成员",
ExcellentMatchSuccessNum: "匹配成功次数",
ExcellentMatchConfirmNum: "匹配确认次数",
ExcellentMatchFreeTimeNum: "匹配免费加时次数",
ExcellentMatchGiftTimeNum: "匹配礼物加时次数",
}
// 关系排序
type RelationUserFormOriginType mysql.Type
const (
//喜欢的用户
RelationUserLike RelationUserFormOriginType = 1
//匹配拒绝用户
RelationMatchRefuse RelationUserFormOriginType = 2
//匹配过的用户
RelationMatchUser RelationUserFormOriginType = 3
//付费发送过消息但没进行过视频聊天
RelationSessionNoMatchConfirm RelationUserFormOriginType = 4
//上一次匹配的用户
RelationMatchUserLastTime RelationUserFormOriginType = 5
)
var RelationMap = map[RelationUserFormOriginType]string{
RelationUserLike: "喜欢的用户",
RelationMatchRefuse: "匹配被拒绝",
RelationMatchUser: "匹配上的用户",
RelationSessionNoMatchConfirm: "付费发送过消息但没进行过视频聊天",
RelationMatchUserLastTime: "上一次匹配的用户",
}
/******匹配确认***********************************/
type MatchConfirmStatus mysql.Type
const (
Success MatchConfirmStatus = 1
Fail MatchConfirmStatus = 2
Temp MatchConfirmStatus = 3
)
type MatchConfirmUserAcceptRefuse mysql.Type
const (
AcceptMatchConfirmUser MatchConfirmUserAcceptRefuse = 1
RefuseMatchConfirmUser MatchConfirmUserAcceptRefuse = 2
)
type MatchCharmUserScoreDetailType = mysql.Type
const (
GiftReceiveCharmType MatchCharmUserScoreDetailType = 1
GiftReceiveVipCharmType MatchCharmUserScoreDetailType = 2
)
type MatchWealthUserScoreDetailType = mysql.Type
const (
GiftReceiveWealthType MatchWealthUserScoreDetailType = 1
GiftReceiveVipWealthType MatchWealthUserScoreDetailType = 2
)
package msg_e
import "git.hilo.cn/hilo-common/resource/mysql"
//消息发送类型,消息接收者是谁 1:通知 2:官网 3:被喜欢通知 (注意:MsgReceiveType 同 MsgUserRecordType 不是树形关系s)
//MsgReceive 结构体服务
type MsgReceiveType = mysql.Type
const (
//小助手的通知
UserMsgReceiveType MsgReceiveType = 1
//系统的通知
SysMsgReceiveType MsgReceiveType = 2
//喜欢消息
LikeMeReceiveType MsgReceiveType = 3
//工会用户通知
TradeUnionReceiveType MsgReceiveType = 4
//用户召回
UserRecall MsgReceiveType = 5
//video请求
VideoSend MsgReceiveType = 6
//访问
VisitReceiveType MsgReceiveType = 7
//拉黑
BlockReceiveType MsgReceiveType = 8
//短信验证码
SmsCode MsgReceiveType = 9
)
//跳转类型 0:无调整 1:网页跳转 2:app跳转 3:跳转到钻石 4:跳转到背包
type ActionType = uint16
const (
NonActionType ActionType = 0
WebActionType ActionType = 1
AppActionType ActionType = 2
)
//消息记录类型(设计的不好,应该是根据消息样式类型设计,而不是业务类型,渣渣)
type MsgUserRecordType = mysql.Type
const (
//新用户
//NewUserType MsgUserRecordType = 1
//举报
ReportType MsgUserRecordType = 2
//喜欢我
//LikeMeType MsgUserRecordType = 3
//重置图片
ResetAvatarType MsgUserRecordType = 4
//
//喜欢我
LikeMeType MsgUserRecordType = 5
//访问
VisitType MsgUserRecordType = 6
//新匹配记录
MatchHistoryType MsgUserRecordType = 7
//互相喜欢
LikeEachType MsgUserRecordType = 8
//你获得s%钻石的礼物收益!
DiamondIncome MsgUserRecordType = 9
//榜单结果
ActivityBillboardResult MsgUserRecordType = 10
//榜单钻石收益
ActivityBillboardDiamond MsgUserRecordType = 11
//榜单坐骑收益
ActivityBillboardProperty MsgUserRecordType = 12
//通过收礼物获得豆子
ActivityBeanProperty MsgUserRecordType = 13
//管理人送钻石
MgrSendDiamondProperty MsgUserRecordType = 14
//群组榜单钻石收益
ActivityGroupBillboardDiamond MsgUserRecordType = 15
//群组榜单坐骑收益
ActivityGroupBillboardProperty MsgUserRecordType = 16
//群组支持收益
GroupSupport MsgUserRecordType = 17
//群组支持提醒结果
GroupSupportResult MsgUserRecordType = 18
//管理人送座驾
MgrSendProperty MsgUserRecordType = 19
//送道具(座驾,头饰都属于道具)
AddProps MsgUserRecordType = 20
//MISS活动获胜
ActivityBillboardBeLikeResult = 21
//CP活动获胜
ActivityBillboardCpResult = 22
//加入势力主
GroupPowerUserJoin = 23
//离开势力主
GroupPowerUserLeave = 24
//贵族
AddNoble = 25
//日充值活动通知
ActivityTriggerDayPay = 26
//也门活动通知
ActivityTriggerYemen = 27
//月充值活动通知
ActivityTriggerMonthPay = 28
FruitTycoonAward = 29 // 水果大亨获奖
LuckyboxRecycle = 30 //幸运盒子回收
HlTemp1 = 31 //产品黄蕾,2022/06/29 临时要求发给某人的小助手消息
HLTemp2 = 32 //问卷调查
NewUserInviteAuditPassed = 33 // 新用户奖励活动审核通过
NewUserInviteAuditFailed = 34 // 新用户奖励活动审核不通过
NewUserInviterAward = 35 // 新用户奖励活动邀请成功数达标
PowerSupportSalary = 36 // 势力扶持工资领取 提醒
CountryStarOrdinaryAward = 37 // 国家之星瓜分奖提醒
GroupActivityRewardMsg = 38 // 群组活动钻石奖励提醒
TemplateActAwardMsg = 39 // 通用模板活动奖励提醒
TemplateSmsCode = 40 // 通用模板活动奖励提醒
AddUserBag = 50 // 赠送背包礼物
)
type MsgSysUserType = mysql.Type
const (
//系统消息
SysType MsgSysUserType = 1
//小助手消息
AssistantType MsgSysUserType = 2
)
//resMsgTransalte 中 msg_type 同 type, msg_type是属于一级类型 type属于二级类型。 msg_type 对应MsgReceiveType type:部分对应MsgUserRecordType MsgUserRecordType(应该是小助手的类型)
type MsgSysRecordType = mysql.Type
const (
//这个值木有意义,
SysMsgSysRecordType1 MsgSysRecordType = 1
SysMsgSysRecordType2 MsgSysRecordType = 2
)
package msg_e
// 公屏消息
type TypePublicScreenMsg uint8
const (
UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组
UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间
UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户
RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色
RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色
ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用
RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果
GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物
GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5
JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息
RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息
LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖
FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖
EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间
)
package property_e
import "git.hilo.cn/hilo-common/resource/mysql"
type UserPropertyUsing = mysql.Type
const (
YesUsing UserPropertyUsing = 1
NoUsing UserPropertyUsing = 0
)
type UserPropertyLogOrginType = mysql.Type
const (
//活动奖励
ActivityBillboardReward UserPropertyLogOrginType = 1
//
Operational UserPropertyLogOrginType = 2
//群组活动
ActivityGroupBillboardReward UserPropertyLogOrginType = 3
//赠送
Send UserPropertyLogOrginType = 4
//火箭游戏
Rocket UserPropertyLogOrginType = 5
//活动阀值触发奖励
ActivityBillboardTrigger UserPropertyLogOrginType = 6
//首次充值奖励
ActivityRechargeFirst UserPropertyLogOrginType = 7
Give UserPropertyLogOrginType = 8
GeneralActivity UserPropertyLogOrginType = 9 // 一般性活动
)
type UserPropertyLogType mysql.Type
const (
AddSecond UserPropertyLogType = 1
UpdateEndTime UserPropertyLogType = 2
Del UserPropertyLogType = 3
)
type PropertyType = uint16
const (
TypeNoble PropertyType = 1
TypeMedal PropertyType = 2
TypeHeaddress PropertyType = 3
TypeRide PropertyType = 4
)
package res_e package res_e
import "hilo-user/resource/mysql" import "git.hilo.cn/hilo-common/resource/mysql"
type MsgIdType = uint type MsgIdType = uint
const ( const (
DEFAULT_LANG = "en" DefaultLang = "en"
MSG_ID_GAME_CREATE MsgIdType = 1001
MSG_ID_GAME_JOIN MsgIdType = 1002
) )
type ResMedalType = mysql.Type 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 type ResMedalScope = mysql.Type
const (
//私有,只能时管理人发放
Private ResMedalScope = 1
//公有,自己获取
Public ResMedalScope = 2
)
type ResNameplateType = mysql.Type type ResNameplateType = mysql.Type
type ResNameplateObtainType = mysql.Type type ResNameplateObtainType = mysql.Type
type ResNameplateScope = mysql.Type type ResNameplateScope = mysql.Type
type ResUserBag = mysql.Type
type ResPropertyAvatarType = mysql.Type
const (
ResUserBagGift ResUserBag = 1 // 背包道具-礼物
)
package user_e package user_e
import "hilo-user/resource/mysql" import (
"git.hilo.cn/hilo-common/resource/mysql"
)
type ThirdPartyType = mysql.Type type ThirdPartyType = mysql.Type
...@@ -12,6 +14,17 @@ const ( ...@@ -12,6 +14,17 @@ const (
WeChat ThirdPartyType = 5 WeChat ThirdPartyType = 5
) )
type CountType mysql.Type
const (
//我喜欢的数量
CountTypeLike CountType = 1
//我拉黑的数量
CountTypeBlock CountType = 2
//我被喜欢的次数
CountTypeLikeMe CountType = 3
)
type UserStatus mysql.Type type UserStatus mysql.Type
const ( const (
...@@ -24,8 +37,33 @@ const ( ...@@ -24,8 +37,33 @@ const (
type UserVipType = mysql.Type type UserVipType = mysql.Type
const ( const (
// //购买
UserMan = 1 UserVipTypeBuy UserVipType = 1
// //赠送
UserWomen = 2 UserVipTypeGive UserVipType = 2
) )
type UserLikeOperateType = mysql.Type
const (
//增加喜欢
LikeAdd UserLikeOperateType = 1
//取消喜欢
LikeCancel UserLikeOperateType = 2
)
type UserLikeSceneType = mysql.Type
const (
Match UserLikeSceneType = 1
Video UserLikeSceneType = 2
)
type InteractionType = mysql.Type
const (
InteractPrivateGift InteractionType = 1
InteractVideo InteractionType = 2
)
package _const
const (
TRACEID = "traceId"
USERID = "userId"
EXTERNAL_ID = "externalId"
CODE = "code"
NICK = "nick"
AVATAR = "avatar"
COUNTRY = "country"
EXTERNALID1 = "externalId1"
EXTERNALID2 = "externalId2"
MGRID = "mgrId"
DEVICETYPE = "deviceType"
DEVICEVERSION = "deviceVersion"
APP_VERSION = "appVersion"
ACTION_RESULt = "actionResult"
URL = "url"
METHOD = "method"
IMEI = "imei"
LANGUAGE = "language"
)
package user_k
import (
"fmt"
)
const (
GameAdd = "user:add:%s"
GameLock = "user:lock:%s"
)
func GetGameAddKey(txGroupId string) string {
return fmt.Sprintf(GameAdd, txGroupId)
}
package group_k
//在房间的人
const groupRoomLiving = "group_room_living"
func GetPrefixGroupRoomLiving() string {
return groupRoomLiving
}
package robot_k
import "fmt"
const (
RobotGroupCd = "robot:group:cd:%s"
)
// 机器人上群cd
func GetRobotGroupCdKey(txGroupId string) string {
return fmt.Sprintf(RobotGroupCd, txGroupId)
}
...@@ -2,8 +2,10 @@ package user_k ...@@ -2,8 +2,10 @@ package user_k
import ( import (
"fmt" "fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/redis_key" "hilo-user/_const/redis_key"
"hilo-user/resource/mysql" "strconv"
"strings"
) )
const ( const (
...@@ -28,3 +30,9 @@ func GetExternalIdToUidKey(externalId mysql.Str) string { ...@@ -28,3 +30,9 @@ func GetExternalIdToUidKey(externalId mysql.Str) string {
func GetCodeToUidKey(code mysql.Str) string { func GetCodeToUidKey(code mysql.Str) string {
return redis_key.ReplaceKey(UserCodeToUIdStr, code) return redis_key.ReplaceKey(UserCodeToUIdStr, code)
} }
const syncTimHiloLock = "sync_tim_hilo_{userId}"
func GetKeySyncTimHilo(userId uint64) string {
return strings.Replace(syncTimHiloLock, "{userId}", strconv.FormatUint(userId, 10), -1)
}
package _const
import (
"encoding/json"
"fmt"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"net"
"runtime/debug"
"strings"
"time"
)
const DEFAULT_LANG = "en"
const DATETIME_FORMAT = "2006-01-02 15:04:05"
const DATE_FORMAT = "2006-01-02"
const DefaultAvatarMan = "hilo/manager/ea48b62d54a24a709de3c38702c89995.png"
func GetZeroTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
// 取最近的一个星期n
func GetLastDayOfWeek(t time.Time, n time.Weekday) time.Time {
weekDay := t.Weekday()
// 校正日期
if weekDay < n {
weekDay = 7 - n + weekDay
} else {
weekDay = weekDay - n
}
return t.AddDate(0, 0, -(int(weekDay)))
}
// 补全url,区分处理oss和aws两种情况
func MakeFullUrl(url string) string {
if strings.HasPrefix(url, config.GetConfigOss().OSS_CDN) || strings.HasPrefix(url, config.GetConfigAws().AWS_CDN) {
return url
} else if strings.HasPrefix(url, "nextvideo/") {
return config.GetConfigOss().OSS_CDN + url
} else if strings.HasPrefix(url, config.GetConfigAws().AWS_DIR) {
return config.GetConfigAws().AWS_CDN + url
} else {
return url
}
}
// 去除slice中的重复元素
func UniqueSliceUInt64(sliceIn []uint64) []uint64 {
sliceOut := make([]uint64, 0, len(sliceIn))
m := make(map[uint64]struct{}, len(sliceIn))
for _, i := range sliceIn {
if _, ok := m[i]; !ok {
m[i] = struct{}{}
sliceOut = append(sliceOut, i)
}
}
return sliceOut
}
func ToString(s interface{}) (string, error) {
b, err := json.Marshal(s)
if err != nil {
return "", nil
}
return string(b), nil
}
func SliceToMapUInt64(s []uint64) map[uint64]struct{} {
m := make(map[uint64]struct{}, len(s))
for _, i := range s {
m[i] = struct{}{}
}
return m
}
func GetClientIp() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", err
}
for _, address := range addrs {
// 检查ip地址判断是否回环地址
if ipNet, ok := address.(*net.IPNet); ok && ipNet.IP.IsGlobalUnicast() {
//if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
return ipNet.IP.String(), nil
}
}
}
return "", fmt.Errorf("can not find the client ip address")
}
func CheckGoPanic() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}
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 cp_cron
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 := domain.CreateModelContext(model.MyContext)
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)
continue
}
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 := domain.CreateModelContext(model.MyContext)
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)
continue
}
time.Sleep(time.Millisecond * 10)
}
})
c.Start()
}
package cron
import (
"git.hilo.cn/hilo-common/resource/config"
"hilo-user/cron/cp_cron"
"hilo-user/cron/gift_cron"
"hilo-user/cron/user_cron"
)
func Init() {
user_cron.SyncGiftRecommendUsers() // 同步送礼推荐用户,多进程都需要执行
if !config.IsMaster() {
return
}
//gift_cron.SendGiftEventInit() // 礼物消息
//gift_cron.GiftRemark() // 礼物消息补偿
gift_cron.SendGiftEvent() // 送礼事件
cp_cron.ClearCpExpire() // 清理过期cp
cp_cron.CpAnniversaryNotice() // cp纪念日
cp_cron.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 gift_cron
import (
"git.hilo.cn/hilo-common/domain"
"github.com/jinzhu/now"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/cache/gift_c"
"hilo-user/domain/event/gift_ev"
"hilo-user/domain/model/cp_m"
"time"
)
// 送礼事件
func SendGiftEvent() {
//if !config.IsMaster() {
// return
//}
go func() {
for true {
model := domain.CreateModelNil()
if sendGiftEvent := gift_c.BLPopQueueSendGift(model); sendGiftEvent != nil {
cpGiftEvent(model, sendGiftEvent) // cp送礼
}
}
}()
}
// 送礼增加cp等级
// 送礼增加cp排行榜
func cpGiftEvent(model *domain.Model, sendGiftEvent *gift_ev.SendGiftEvent) {
// 只处理cp礼物
if !sendGiftEvent.ResGift.Cp {
return
}
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, sendGiftEvent.SceneUid); 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 // 业务场景允许提前break(cp是唯一的)
}
}
}
package user_cron
import (
"git.hilo.cn/hilo-common/domain"
"github.com/robfig/cron"
"hilo-user/domain/model/recommend_m"
)
// 定期同步礼物推荐用户
func SyncGiftRecommendUsers() {
go recommend_m.SyncPastTop50SendGiftUsers(domain.CreateModelNil()) // 启动先同步一次
c := cron.New()
spec := "0 */5 * * * ?"
_ = c.AddFunc(spec, func() {
var model = domain.CreateModelNil()
recommend_m.SyncPastTop50SendGiftUsers(model)
})
c.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/_const/enum/cp_e"
"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"`
}
// cp进场特效信息
type CvCpEntryEffect struct {
CpLevel cp_e.CpLevel `json:"cpLevel"`
CpUserAvatar string `json:"cpUserAvatar"`
CpEntryEffect bool `json:"cpEntryEffect"`
}
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.CvUserLittle `json:"user1"` // user1
User2 *user_cv.CvUserLittle `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], "", "", false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeSpace]}
CvPrivilege2 = CvPrivilege{cp_e.CpPrivilegeBanner, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeBanner], "", cp_e.CpPrivilegeDescMsgId[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], "", "", false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeMedal]}
CvPrivilege4 = CvPrivilege{cp_e.CpPrivilegeCert, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeCert], "", cp_e.CpPrivilegeDescMsgId[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], "", "", true, false, CpPrivilegeLevelList[cp_e.CpPrivilegeRoomEffect]}
CvPrivilege6 = CvPrivilege{cp_e.CpPrivilegeHeadwear, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeHeadwear], "", cp_e.CpPrivilegeDescMsgId[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], "", "", true, false, CpPrivilegeLevelList[cp_e.CpPrivilegeActiveProfile]}
CvPrivilege8 = CvPrivilege{cp_e.CpPrivilegeMicEffect, cp_e.CpPrivilegeNameMsgId[cp_e.CpPrivilegeMicEffect], "", cp_e.CpPrivilegeDescMsgId[cp_e.CpPrivilegeMicEffect], "", "", false, false, CpPrivilegeLevelList[cp_e.CpPrivilegeMicEffect]}
)
var CpLevelPrivilegeList = map[cp_e.CpLevel][]CvPrivilege{
cp_e.CpLevel0: {CvPrivilege1, CvPrivilege4},
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)
privileges[i].Icon = cp_e.CpPrivilegeIcon[v.Type][Level]
}
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/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/cp_m"
"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"`
ReverseEffectUrl mysql.Str `json:"reverseEffectUrl"`
TimeLeft int64 `json:"timeLeft"` // 离到期还有多少秒(过期则是负数)
HeadwearIcon string `json:"headwearIcon"`
}
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,
ReverseEffectUrl: resHwMap[i.HeadwearId].ReverseEffectUrl,
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,
ReverseEffectUrl: resHeadwear.ReverseEffectUrl,
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]
}
// cp 相关
var model = domain.CreateModelNil()
cpRelations := cp_m.MGetCpRelation(model, userIds)
var m = make(map[uint64]cp_m.CpRelation)
var cpUserIds []uint64
for i, v := range cpRelations {
m[v.UserId1] = cpRelations[i]
m[v.UserId2] = cpRelations[i]
cpUserIds = append(cpUserIds, v.UserId1)
cpUserIds = append(cpUserIds, v.UserId2)
}
users, _ := user_m.GetUserMapByIds(model, cpUserIds)
var response = make(map[uint64]string)
for _, uid := range userIds {
if cpRelation, ok := m[uid]; ok {
cpUserId := cpRelation.UserId2
if cpUserId == uid {
cpUserId = cpRelation.UserId1
}
response[uid] = users[cpUserId].Avatar
}
}
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,
ReverseEffectUrl: headwear.ReverseEffectUrl,
Using: r.Using == headwear_e.YesUsing,
HeadwearIcon: response[r.UserId],
}
}
}
return result, nil
}
package invite_cv
import "git.hilo.cn/hilo-common/resource/mysql"
type CvUserLevel struct {
UserId mysql.ID `json:"userId"` // 用户id
WealthUserGrade uint32 `json:"wealthUserGrade"` // 财富等级
CharmUserGrade uint32 `json:"charmUserGrade"` // 魅力等级
ActiveUserGrade uint32 `json:"activeUserGrade"` // 活跃等级
NobleLevel uint16 `json:"nobleLevel"` // 贵族等级
}
type InviteApplyRes struct {
List []*InviteApply `json:"list"`
NumList []*InviteApplyNumRes `json:"numList"`
MyCode string `json:"myCode"`
}
type InviteApply struct {
NewUserCode string `json:"newUserCode"`
Platform string `json:"platform"`
Recharge string `json:"recharge"`
UserCode string `json:"userCode"`
CreateUnix int64 `json:"createUnix"`
Level string `json:"level"`
Status uint8 `json:"status"` // 状态0.未审核1.已通过2.已拒绝
Avatar string `json:"avatar"`
ExternalId string `json:"externalId"`
Reason int `json:"reason"` // 1.已申请2.待审核3.已通过4.已拒绝"
Country string `json:"country"`
PlatformId string `json:"platformId"`
}
type InviteApplyNumRes struct {
Type int `json:"type"` // 1.已申请2.待审核3.已通过4.已拒绝"
Num int `json:"num"`
}
type AgentPeriod struct {
Week []AgentPeriodWeek `json:"week"`
}
type AgentPeriodWeek struct {
StartDate string `json:"startDate"`
EndDate string `json:"endDate"`
}
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, area int) (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{Area: area}).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
}
package user_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
)
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"` // 有效天数
TextStyleList []*TextStyle `json:"textStyleList"` // 文本样式
HasGiftText bool `json:"hasGiftText"` // 是否有礼物文字
}
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/resource/mysql"
type MGetUserLevelData map[mysql.ID]CvUserLevel
type CvUserLevel struct {
UserId mysql.ID `json:"userId"` // 用户id
WealthUserGrade uint32 `json:"wealthUserGrade"` // 财富等级
CharmUserGrade uint32 `json:"charmUserGrade"` // 魅力等级
ActiveUserGrade uint32 `json:"activeUserGrade"` // 活跃等级
NobleLevel uint16 `json:"nobleLevel"` // 贵族等级
}
package user_cv
import (
"encoding/json"
"git.hilo.cn/hilo-common/_const/common"
"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/_const/enum/country_e"
"hilo-user/_const/enum/cp_e"
"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"` // 是否靓号
Birthday uint64 `json:"birthday"`
}
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(),
Birthday: user.Birthday,
}
}
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"` // 是否靓号
IsNew bool `json:"isNew"` // 是否新用户
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结构,等级+权限
Medals []uint32 `json:"medals"` // 勋章列表
MedalInfo []medal_cv.CvMedal `json:"medalInfo"` // 勋章列表
Headwear *headwear_cv.CvHeadwear `json:"headwear"` // 当前使用的头饰
Ride property_cv.CvProperty `json:"ride"` // 当前使用的座驾
Noble noble_cv.CvNoble `json:"noble"` // 当前的
GroupRole common.GroupRoleType `json:"groupRole"` // 在群组的角色
}
type CvUserLittle struct {
//不会有返回值
Id *mysql.ID `json:"id,omitempty"`
//头像,不存在为nil
Avatar *string `json:"avatar"`
//用户对外ID
ExternalId *string `json:"externalId"`
//昵称,不存在为nil
Nick *string `json:"nick"`
}
//批量获取用户基本信息
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)
propertiesArea := make(map[int]map[uint64]property_cv.CvProperty)
for _, v := range []int{1, 2} {
properties, err := GetPropertyAll(mysql.Db, v)
if err != nil {
return nil, err
}
propertiesArea[v] = properties
}
areaMap, err := user_m.GetUserAreaMap(domain.CreateModelNil(), userIds)
if err != nil {
return nil, err
}
nobles, err := noble_m.BatchGetActiveNoble(domain.CreateModelNil(), userIds)
if err != nil {
return nil, err
}
superManagerMap, err := user_m.GetSuperManagerMap(userIds)
if err != nil {
return nil, err
}
cvUserBases := []*CvUserBase{}
for i := 0; i < len(users); i++ {
user := users[i]
properties := propertiesArea[areaMap[user.ID]]
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(),
IsNew: user.IsNew(),
IsVip: vips[user.ID] != nil,
IsOfficialStaff: superManagerMap[user.ID],
Medals: IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals[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
}
// 获取cp另一半基本信息
func GetUserBaseForCpMap(userIds []mysql.ID) (map[mysql.ID]*CvUserBase, error) {
var res = make(map[mysql.ID]*CvUserBase)
users, err := GetUserBasesForCp(userIds)
if err != nil {
return nil, err
}
for i, v := range users {
if v.Id != nil {
res[*v.Id] = users[i]
}
}
return res, nil
}
// 批量获取cp另一半基本信息
func GetUserBasesForCp(userIds []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)
}
headwearMap, err := headwear_cv.BatchGetCvHeadwears(userIds)
if err != nil {
return nil, err
}
nobles, err := noble_m.BatchGetActiveNoble(domain.CreateModelNil(), userIds)
if err != nil {
return nil, err
}
var cvUserBases []*CvUserBase
for i := 0; i < len(users); i++ {
user := users[i]
invisible := IfLogout(user.LogoutTime)
invisibleAvatar := ""
invisibleNick := user.Code
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(),
IsNew: user.IsNew(),
IsVip: vips[user.ID] != nil,
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)
}
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, area int) (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{Area: area}).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 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"`
}
//用户详细信息
type CvUserDetail struct {
CvUserBase
//统计:我喜欢多少人
ILikeCount *uint32 `json:"iLikeCount"`
//统计:多少人喜欢你, (本才才有数据,不是本人,数据为nil)
LikeCount *uint32 `json:"likeCount"`
//统计:多少人访问你
VisitCount *uint32 `json:"visitCount"`
//消息提醒, 1:开启,2:关闭
IsPush *uint8 `json:"isPush"`
//钻石数量(本人才有数据,不是本人,数据为nil)
DiamondNum *uint32 `json:"diamondNum"`
//粉钻数量(本人才有数据,不是本人,数据为nil)
PinkDiamondNum *uint32 `json:"pinkDiamondNum"`
//是否喜欢(本人没有数据,//20210205 已废弃nil,产品说:可以自己喜欢自己)
IsLike *bool `json:"isLike"`
//ID
//ID *mysql.ID `json:"id,omitempty"`
//是否工会成员, 只有是自己查自己,这个才有值,其它全为nil
//IsTradeUnion *bool `json:"isTradeUnion"`
//工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值,
//IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"`
//是否可以免费通话,自己本人没有数据
//IsVideoFreeCan *bool `json:"isVideoCanFree"`
//别人是否喜欢我,自己本人没有数据 (20210205 已废弃nil,产品说:可以自己喜欢自己)
IsLikeMe *bool `json:"isLikeMe"`
HeartValue uint32 `json:"heartValue"` // 与我之间永恒之心的值
HeartValueMax uint32 `json:"heartValueMax"` // 与我之间永恒之心的最大值(0代表没有永恒之心,即没有相互关注)
MeetDays uint `json:"meetDays"` // 成长关系建立的时间(天数)
WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级
CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级
ActivityUserGrade uint32 `json:"activityUserGrade"` //活跃等级
CurrentRoom string `json:"currentRoom"` // 当前用户所在房间(产品叫“群组”)
MyGroupPower uint64 `json:"myGroupPower"` // 当前用户所在势力
MyGroupPowerName string `json:"myGroupPowerName"` // 当前用户所在势力绑定群组的名称
GroupPower rpc.CvGroupPowerInfo `json:"groupPower"` // 家族
GroupId string `json:"groupId"` // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个
PhoneInfo *user_m.UserPhoneInfo `json:"phoneInfo"` // 用户绑定的手机信息
ThirdList []int8 `json:"thirdList"` // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5)
CountryManager *CVCountryManager `json:"countryManager,omitempty"` // 国家管理员
Cp *CvCp `json:"cp,omitempty"` // cp信息
}
//用户详细信息-在房间里面时需要的
type CvUserDetailRoom 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"`
//性别 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"` // 是否靓号
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
//是否展示年龄, 是本人才有数据,看其他用户均为nil
IsShowAge *uint8 `json:"isShowAge"`
//是否VIP用户
IsVip bool `json:"isVip"`
Svip rpc.CvSvip `json:"svip"` // svip结构,等级+权限
Medals []uint32 `json:"medals"` // 勋章列表
Noble noble_cv.CvNoble `json:"noble"` // 当前的
CountryManager *CVCountryManager `json:"countryManager,omitempty"` // 国家管理员
Headwear *headwear_cv.CvHeadwear `json:"headwear"` // 当前使用的头饰
WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级
CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级
ActivityUserGrade uint32 `json:"activityUserGrade"` //活跃等级
GroupPower rpc.CvGroupPowerInfo `json:"groupPower"` // 家族
//是否喜欢(本人没有数据,//20210205 已废弃nil,产品说:可以自己喜欢自己)
IsLike *bool `json:"isLike"`
//别人是否喜欢我,自己本人没有数据 (20210205 已废弃nil,产品说:可以自己喜欢自己)
IsLikeMe *bool `json:"isLikeMe"`
Cp *CvCpTiny `json:"cp,omitempty"` // cp信息
GroupRole common.GroupRoleType `json:"groupRole"` // 在群组的角色
}
// cv国家管理人员
type CVCountryManager struct {
Country string `json:"country"` // 国家name
Role country_e.CountryMgrRole `json:"role" swaggertype:"integer"` // 角色 1:国家管理员 2:国家助理
}
// cp信息
type CvCp struct {
CpUserInfo *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 CvCpTiny struct {
CpUserInfo *CvCpUser `json:"cpUserInfo"` // cp用户信息
CpLevel CvCpLevel `json:"cpLevel"` // cp等级
MyPrivilegeList []CvPrivilege `json:"myPrivilegeList"` // 等级特权
CreatedUnix int64 `json:"createdUnix"` // cp创建时间
CpDays int `json:"cpDays"` // cp天数
}
type CvCpUser struct {
//不会有返回值
Id *mysql.ID `json:"id,omitempty"`
//头像,不存在为nil
Avatar *string `json:"avatar"`
//用户对外ID
ExternalId *string `json:"externalId"`
//昵称,不存在为nil
Nick *string `json:"nick"`
//性别 1:男 2:女,不存在为nil
Sex *uint8 `json:"sex"`
//邀请码
Code *string `json:"code"`
Headwear *headwear_cv.CvHeadwear `json:"headwear"` // 当前使用的头饰
Svip rpc.CvSvip `json:"svip"` // svip结构,等级+权限
Noble noble_cv.CvNoble `json:"noble"` // 当前的
}
// cp关系
type CvCpRelation struct {
CpId uint64 `json:"cpId"`
UserId uint64 `json:"userId"`
CpUserId uint64 `json:"cpUserId"`
CpUserAvatar string `json:"cpUserAvatar,omitempty"`
}
// 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值
Title string `json:"title,omitempty"` // 称号翻译
}
// 特权信息
type CvPrivilege struct {
Type cp_e.CpPrivilege `json:"type"` // 特权id 1:空间 2:横幅 3:等级勋章 4:证书 5:进场特效 6:头像头饰 7:动态资料卡 8:麦位特效
}
func UserBaseToUserLittle(base *CvUserBase) *CvUserLittle {
return &CvUserLittle{
Id: base.Id,
Avatar: base.Avatar,
ExternalId: base.ExternalId,
Nick: base.Nick,
}
}
func CvUserDetailToCvUserDetailRoom(info *CvUserDetail) *CvUserDetailRoom {
res := new(CvUserDetailRoom)
jData, _ := json.Marshal(info)
_ = json.Unmarshal(jData, &res)
return res
}
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 IfLogoutMedals(condition bool, trueVal, falseVal []uint32) []uint32 {
if condition {
return trueVal
}
return falseVal
}
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
}
...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code ...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code
[REDIS] [REDIS]
REDIS_HOST=47.244.34.27:6379 REDIS_HOST=47.244.34.27:6379
REDIS_PASSWORD=8QZ9JD1zLvPR3yHf REDIS_PASSWORD=8QZ9JD1zLvPR3yHf
REDIS_CLUSTER_HOST=47.244.34.27:6379
REDIS_CLUSTER_PASSWORD=8QZ9JD1zLvPR3yHf
[JWT] [JWT]
SECRET=hilo1632 SECRET=hilo1632
ISSUER_API=hiloApi ISSUER_API=hiloApi
......
package gift_c
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"github.com/go-redis/redis/v8"
"hilo-user/domain/event/gift_ev"
"time"
)
const EventSendGiftHiloUserQueue = "send:gift:queue:hilo_user"
// redis pop event sendGift
func BLPopQueueSendGift(model *domain.Model) *gift_ev.SendGiftEvent {
var res *gift_ev.SendGiftEvent
queue := EventSendGiftHiloUserQueue
strs, err := model.RedisCluster.BLPop(model, time.Second, queue).Result()
if err != nil {
if err != redis.Nil {
model.Log.Errorf("BLPopQueueSendGift fail:%v", err)
}
return nil
}
if len(strs) >= 2 {
content := strs[1]
res = new(gift_ev.SendGiftEvent)
if err := json.Unmarshal([]byte(content), res); err != nil {
model.Log.Errorf("BLPopQueueSendGift json fail:%v", err)
return nil
}
return res
}
return nil
}
...@@ -2,7 +2,7 @@ package cache ...@@ -2,7 +2,7 @@ package cache
import ( import (
"encoding/json" "encoding/json"
"hilo-user/domain" "git.hilo.cn/hilo-common/domain"
"math/rand" "math/rand"
"time" "time"
) )
...@@ -27,7 +27,7 @@ func SetJSON(model *domain.Model, key string, obj interface{}) (err error) { ...@@ -27,7 +27,7 @@ func SetJSON(model *domain.Model, key string, obj interface{}) (err error) {
if err != nil { if err != nil {
return err return err
} }
return model.Redis.Set(model.Context, key, value, DEFAULT_TTL).Err() return model.RedisCluster.Set(model.Context, key, value, DEFAULT_TTL).Err()
} }
// 获取redis中json结构体 // 获取redis中json结构体
...@@ -37,7 +37,7 @@ func GetJSON(model *domain.Model, key string, obj interface{}) (err error) { ...@@ -37,7 +37,7 @@ func GetJSON(model *domain.Model, key string, obj interface{}) (err error) {
defer func() { defer func() {
model.Log.Infof("GetJson key:%v,value:%s,obj:%v,err:%v", key, value, obj, err) model.Log.Infof("GetJson key:%v,value:%s,obj:%v,err:%v", key, value, obj, err)
}() }()
value, err = model.Redis.Get(model.Context, key).Bytes() value, err = model.RedisCluster.Get(model.Context, key).Bytes()
if err != nil { if err != nil {
// may redisV2.Nil // may redisV2.Nil
return return
...@@ -59,7 +59,7 @@ func TryLock(model *domain.Model, key string, acquireTimeout, expireTimeout time ...@@ -59,7 +59,7 @@ func TryLock(model *domain.Model, key string, acquireTimeout, expireTimeout time
if time.Now().After(deadline) { if time.Now().After(deadline) {
return false return false
} }
flag, err := model.Redis.SetNX(model, key, "1", expireTimeout).Result() flag, err := model.RedisCluster.SetNX(model, key, "1", expireTimeout).Result()
if err != nil || !flag { if err != nil || !flag {
time.Sleep(time.Millisecond * 10) time.Sleep(time.Millisecond * 10)
} else { } else {
...@@ -70,5 +70,5 @@ func TryLock(model *domain.Model, key string, acquireTimeout, expireTimeout time ...@@ -70,5 +70,5 @@ func TryLock(model *domain.Model, key string, acquireTimeout, expireTimeout time
// 解锁 // 解锁
func UnLock(model *domain.Model, key string) { func UnLock(model *domain.Model, key string) {
model.Redis.Del(model, key) model.RedisCluster.Del(model, key)
} }
package user_c package user_c
import ( 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" redisV8 "github.com/go-redis/redis/v8"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"hilo-user/_const/redis_key/user_k" "hilo-user/_const/redis_key/user_k"
"hilo-user/domain"
"hilo-user/domain/cache" "hilo-user/domain/cache"
"hilo-user/domain/model/user_m" "hilo-user/domain/model/user_m"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"hilo-user/resource/mysql" "time"
) )
// 获取用户简要信息 // 获取用户简要信息
...@@ -50,7 +53,7 @@ func ToUserId(model *domain.Model, externalId mysql.Str) (mysql.ID, error) { ...@@ -50,7 +53,7 @@ func ToUserId(model *domain.Model, externalId mysql.Str) (mysql.ID, error) {
if externalId == "" { if externalId == "" {
return 0, myerr.NewSysError("externalId 不能为空") return 0, myerr.NewSysError("externalId 不能为空")
} }
userId, err := model.Redis.Get(model.Context, user_k.GetExternalIdToUidKey(externalId)).Int64() userId, err := model.RedisCluster.Get(model.Context, user_k.GetExternalIdToUidKey(externalId)).Int64()
if err != nil && err != redisV8.Nil { if err != nil && err != redisV8.Nil {
return 0, err return 0, err
} }
...@@ -73,7 +76,7 @@ func ToUserIdByCode(model *domain.Model, code mysql.Str) (mysql.ID, error) { ...@@ -73,7 +76,7 @@ func ToUserIdByCode(model *domain.Model, code mysql.Str) (mysql.ID, error) {
if code == "" { if code == "" {
return 0, myerr.NewSysError("code 不能为空") return 0, myerr.NewSysError("code 不能为空")
} }
userId, err := model.Redis.Get(model.Context, user_k.GetCodeToUidKey(code)).Int64() userId, err := model.RedisCluster.Get(model.Context, user_k.GetCodeToUidKey(code)).Int64()
if err != nil && err != redisV8.Nil { if err != nil && err != redisV8.Nil {
return 0, err return 0, err
} }
...@@ -96,16 +99,17 @@ func ToUserIdByCode(model *domain.Model, code mysql.Str) (mysql.ID, error) { ...@@ -96,16 +99,17 @@ func ToUserIdByCode(model *domain.Model, code mysql.Str) (mysql.ID, error) {
// 顺手缓存code->userId // 顺手缓存code->userId
// param user: 已经在上层获取的db User结构 // param user: 已经在上层获取的db User结构
func cacheUserTiny(model *domain.Model, user *user_m.User) error { func cacheUserTiny(model *domain.Model, user *user_m.User) error {
userTiny := new(user_m.UserTiny) userTiny := ToUserTinyBy(user)
if err := copier.Copy(userTiny, user); err != nil { //userTiny := new(user_m.UserTiny)
return err //if err := copier.Copy(userTiny, user); err != nil {
} // return err
//}
// cache externalId->userId // cache externalId->userId
if err := model.Redis.SetEX(model.Context, user_k.GetExternalIdToUidKey(user.ExternalId), user.ID, cache.GetDefaultTTL()).Err(); err != nil { if err := model.RedisCluster.SetEX(model.Context, user_k.GetExternalIdToUidKey(user.ExternalId), user.ID, cache.GetDefaultTTL()).Err(); err != nil {
return err return err
} }
// cache code->userId // cache code->userId
if err := model.Redis.SetEX(model.Context, user_k.GetCodeToUidKey(user.Code), user.ID, cache.GetDefaultTTL()).Err(); err != nil { if err := model.RedisCluster.SetEX(model.Context, user_k.GetCodeToUidKey(user.Code), user.ID, cache.GetDefaultTTL()).Err(); err != nil {
return err return err
} }
if err := cache.SetJSON(model, user_k.GetUserTinyKey(user.ID), userTiny); err != nil { if err := cache.SetJSON(model, user_k.GetUserTinyKey(user.ID), userTiny); err != nil {
...@@ -113,3 +117,89 @@ func cacheUserTiny(model *domain.Model, user *user_m.User) error { ...@@ -113,3 +117,89 @@ func cacheUserTiny(model *domain.Model, user *user_m.User) error {
} }
return nil 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 domain
import (
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-user/mycontext"
)
type CtxAndDb struct {
Db *gorm.DB
*mycontext.MyContext
Redis *redis.Client
}
package domain
//异步执行的接口
type AsyncEvent interface {
AsyncDo(model *Model, eventData interface{}, n int) error
AsyncSize() int
AsyncNoTxDo(model *Model, eventData interface{}, n int) error
AsyncNoTxSize() int
}
package event
import "hilo-user/domain"
// 程序内部事件
type Base struct {
//同步执行
SyncList []func(model *domain.Model, event interface{}) error
//异步执行
AsyncList []func(model *domain.Model, event interface{}) error
}
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 user_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/resource/mysql"
)
//注册监听
var userEditEvent = new(event.Base)
/**
注册事件
*/
type GameEditEvent struct {
GameId mysql.ID `json:"userId"` // 游戏id
TxGroupId mysql.Str `json:"txGroupId"` // 群组id
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGameEditEventSync(callback func(model *domain.Model, event interface{}) error) {
userEditEvent.SyncList = append(userEditEvent.SyncList, callback)
}
//加入到异步操作中
func AddGameEditEventAsync(callback func(model *domain.Model, event interface{}) error) {
userEditEvent.AsyncList = append(userEditEvent.AsyncList, callback)
}
//领域事件发布
func PublishGameEditEvent(model *domain.Model, event interface{}) error {
//执行同步的领域事件
for _, callback := range userEditEvent.SyncList {
if err := callback(model, event); err != nil {
return err
}
}
// 执行异步的领域事件
if len(userEditEvent.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range userEditEvent.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("userEditEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package user_ev
import (
"hilo-user/_const"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/resource/mysql"
)
//注册监听
var reportGameInfoEvent = new(event.Base)
/**
注册事件
*/
type ReportGameInfoEvent struct {
UserId mysql.ID `json:"uid"` // 用户id,请求get_user_info 接口返回uid参数
ReportType user_e.ReportType `json:"report_type"` // 上报类型 user_start|user_settle
GameStartObject *GameStartObject `json:"user_start_object"` // user_start对应结构体
GameSettleObject *GameSettleObject `json:"user_settle_object"` // user_settle对应结构体
}
type GameStartObject struct {
MgId uint64 `json:"mg_id"` // 游戏id
MgIdStr string `json:"mg_id_str"` // 小游戏id数值型兼容字段(nodejs服务请使用当前字段)
RoomId string `json:"room_id"` // 接入方房间id
GameMode int32 `json:"user_mode"` // 游戏模式,设定游戏的一些功能(参与游戏的人数,出手时间,特定的玩法)
GameRoundId string `json:"user_round_id"` // 本局游戏的id (重复上报,使用该字段去重)
BattleStartAt int32 `json:"battle_start_at"` // 战斗开始时间(秒)
Players []PlayerObject `json:"players"` // player_object 数组
ReportGameInfoExtras string `json:"report_user_info_extras"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过1024字节,超过则截断
ReportGameInfoKey string `json:"report_user_info_key"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过64字节,超过则截断。接入方服务端可以根据这个字段来查询一局游戏的数据
}
type PlayerObject struct {
Uid string `json:"uid"` // 接入方uid,机器人为空字符
IsAi int32 `json:"is_ai"` // 0:普通用户,1:机器人
}
type GameSettleObject struct {
MgId uint64 `json:"mg_id"` // 游戏id
MgIdStr string `json:"mg_id_str"` // 小游戏id数值型兼容字段(nodejs服务请使用当前字段)
RoomId string `json:"room_id"` // 接入方房间id
GameMode int32 `json:"user_mode"` // 游戏模式
GameRoundId string `json:"user_round_id"` // 本局游戏的id (重复上报,使用该字段去重)
BattleStartAt uint32 `json:"battle_start_at"` // 战斗开始时间(秒)
BattleEndAt uint32 `json:"battle_end_at"` // 战斗结束时间(秒)
BattleDuration int32 `json:"battle_duration"` // 战斗总时间(秒)
Results []PlayerResultObject `json:"results"` // player_result_object 数组
ReportGameInfoExtras string `json:"report_user_info_extras"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过1024字节,超过则截断
ReportGameInfoKey string `json:"report_user_info_key"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过64字节,超过则截断。接入方服务端可以根据这个字段来查询一局游戏的数据
}
type PlayerResultObject struct {
Uid string `json:"uid"` // 接入方uid,机器人为空字符
Rank int32 `json:"rank"` // 排名从1开始,平局排名相同
IsEscaped int32 `json:"is_escaped"` // 0:正常,1:逃跑
IsAi int32 `json:"is_ai"` // 0:普通用户,1:机器人
Role int32 `json:"role"` // 0:表示没有角色信息,玩家在游戏中的角色 游戏role 说明
Score int32 `json:"score"` // 玩家当前局得到的分数
IsWin int32 `json:"is_win"` // 结果 0:表示没有信息,1:输,2:赢,3:平局
Award int32 `json:"award"` // 奖励
Extras string `json:"extras"` // 扩展参数扩展说明
IsManaged int32 `json:"is_managed"` // 是否托管 0:未托管 1:托管
Diamond int64 `json:"diamond"` // 钻石收益,有可能负数,后期计算
LudoExtras *LudoExtras
}
type LudoExtras struct {
Color int `json:"color"`
Steps int `json:"steps"`
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddReportGameInfoEventSync(callback func(model *domain.Model, event interface{}) error) {
reportGameInfoEvent.SyncList = append(reportGameInfoEvent.SyncList, callback)
}
//加入到异步操作中
func AddReportGameInfoEventAsync(callback func(model *domain.Model, event interface{}) error) {
reportGameInfoEvent.AsyncList = append(reportGameInfoEvent.AsyncList, callback)
}
//领域事件发布
func PublishReportGameInfoEvent(model *domain.Model, event interface{}) error {
//执行同步的领域事件
for _, callback := range reportGameInfoEvent.SyncList {
if err := callback(model, event); err != nil {
return err
}
}
// 执行异步的领域事件
if len(reportGameInfoEvent.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range reportGameInfoEvent.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("ReportGameInfoEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
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 group_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
var groupInListen = new(event.Base)
// 进房事件
type GroupInEvent struct {
GroupId string // imGroupId
UserId mysql.ID
ExternalId string
Nick string
Avatar string
IsMember bool //是否永久成员
IsVip bool
NobleLevel uint16
}
func AddGroupInEventSync(callback func(model *domain.Model, event interface{}) error) {
groupInListen.SyncList = append(groupInListen.SyncList, callback)
}
func AddGroupInEventAsync(callback func(model *domain.Model, event interface{}) error) {
groupInListen.AsyncList = append(groupInListen.AsyncList, callback)
}
func PublishGroupInEvent(model *domain.Model, event interface{}) error {
// 执行同步的领域事件
for _, callback := range groupInListen.SyncList {
if err := callback(model, event); err != nil {
return myerr.WrapErr(err)
}
}
// 执行异步的领域事件
if len(groupInListen.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range groupInListen.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("GroupInEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package group_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
var groupLeaveListen = new(event.Base)
// 离房事件
type GroupLeaveEvent struct {
GroupId string
UserId mysql.ID
ExternalId string
}
func AddGroupLeaveEventSync(callback func(model *domain.Model, event interface{}) error) {
groupLeaveListen.SyncList = append(groupLeaveListen.SyncList, callback)
}
func AddGroupLeaveEventAsync(callback func(model *domain.Model, event interface{}) error) {
groupLeaveListen.AsyncList = append(groupLeaveListen.AsyncList, callback)
}
func PublishGroupLeaveEvent(model *domain.Model, event interface{}) error {
// 执行同步的领域事件
for _, callback := range groupLeaveListen.SyncList {
if err := callback(model, event); err != nil {
return myerr.WrapErr(err)
}
}
// 执行异步的领域事件
if len(groupLeaveListen.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range groupLeaveListen.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("GroupInEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package user_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
//注册监听
var userBagSendListen = new(domain.EventBase)
type UserBagSendEvent struct {
UserId mysql.ID
ResType mysql.Type // 道具类型 1:礼物道具
ResId mysql.ID // 道具资源id
Count mysql.Num // 下发数量
Day int // 天数
Reason string // 原因
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddUserBagSendSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(userBagSendListen, callback)
}
//加入到异步操作中
func AddUserBagSendAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(userBagSendListen, callback)
}
//领域事件发布
func PublishUserBagSend(model *domain.Model, event interface{}) error {
return domain.PublishEvent(userBagSendListen, model, event)
}
package domain
import (
"gorm.io/gorm"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
)
type Model struct {
*CtxAndDb `gorm:"-"`
}
func CreateModel(ctxAndDb *CtxAndDb) *Model {
return &Model{CtxAndDb: ctxAndDb}
}
func CreateModelContext(myContext *mycontext.MyContext) *Model {
return &Model{
CtxAndDb: &CtxAndDb{
Db: mysql.Db,
MyContext: myContext,
Redis: redisCli.GetRedis(),
},
}
}
func CreateModelNil() *Model {
return &Model{
CtxAndDb: &CtxAndDb{
Db: mysql.Db,
MyContext: mycontext.CreateMyContext(nil),
Redis: redisCli.GetRedis(),
},
}
}
func (m *Model) DB() *gorm.DB {
return m.Db.WithContext(m)
}
// 包装事务
// 注意:需要使用新的model
func (m *Model) Transaction(f func(*Model) error) error {
// 公用context
// 新的db
txModel := CreateModelContext(m.MyContext)
txModel.Db = m.Db.Begin().WithContext(m)
err := f(txModel)
if err != nil {
txModel.Db.Rollback()
return err
}
return txModel.Db.Commit().Error
}
package bag_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm/clause"
"hilo-user/_const/enum/res_e"
"hilo-user/domain/event/user_ev"
"time"
)
type UserBag struct {
mysql.Entity
UserId mysql.ID
ResType mysql.Type // 资源类型 1:礼物
ResId mysql.ID
Count mysql.Num
EndTime time.Time
}
type UserBagDetail struct {
mysql.Entity
UserId mysql.ID
BagId mysql.ID
ResType mysql.Type // 资源类型 1:礼物
ResId mysql.ID
Count mysql.Num
AddReduce mysql.AddReduce
BefNum mysql.Num
AftNum mysql.Num
Remark mysql.Str
}
// 获取用户有效的背包
// param userId 用户id
// param resType 背包类型 1:礼物
// condition
// 1.获取end_time未到期的
// 2.数量大于0的
func GetUserValidUserBag(model *domain.Model, userId mysql.ID, resType res_e.ResUserBag) ([]*UserBag, error) {
var res []*UserBag
if err := model.DB().Model(UserBag{}).
Where("end_time > ?", time.Now()).
Where("count > 0").
Where("res_type = ?", resType).
Where("user_id = ?", userId).
Order("id").Find(&res).Error; err != nil {
return nil, err
}
return res, nil
}
// 获取指定背包
func GetUserBag(model *domain.Model, bagId mysql.ID) (*UserBag, error) {
res := new(UserBag)
if err := model.DB().Model(UserBag{}).
Where("id = ?", bagId).First(res).Error; err != nil {
return nil, err
}
return res, nil
}
// 增加用户背包
// param userId 用户id
// param resType 道具类型
// param resId 道具id
// param count 增加数量
// param day 增加天数
// condition:
// 0.事务操作
// 1.背包表
// 2.明细表
// return bagId
func AddUserBag(model *domain.Model, userId mysql.ID, resType mysql.Type, resId mysql.ID, count mysql.Num, day int, reason string) (mysql.ID, error) {
var bagId mysql.ID
err := model.Transaction(func(model *domain.Model) error {
// 1.背包表
endTime := time.Now().AddDate(0, 0, day)
userBag := &UserBag{
UserId: userId,
ResType: resType,
ResId: resId,
Count: count,
EndTime: endTime,
}
if err := model.DB().Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}, {Name: "res_type"}, {Name: "res_id"}, {Name: "end_time"}},
DoUpdates: clause.AssignmentColumns([]string{"count"}),
}).Create(userBag).Error; err != nil {
return err
}
bagId = userBag.ID // 自增id
// 2.明细表
userBagDetail := &UserBagDetail{
UserId: userId,
BagId: userBag.ID,
ResType: resType,
ResId: resId,
Count: count,
AddReduce: mysql.ADD,
BefNum: 0, // 加背包的统一为0
AftNum: count, // 加背包统一为count,因为每次加几乎不可能是一样的
Remark: reason,
}
if err := model.DB().Create(userBagDetail).Error; err != nil {
return err
}
return user_ev.PublishUserBagSend(model, &user_ev.UserBagSendEvent{
UserId: userId,
ResType: resType,
ResId: resId,
Count: count,
Day: day,
Reason: reason,
})
})
return bagId, err
}
package common package common
import ( import (
"context" "git.hilo.cn/hilo-common/resource/mysql"
"encoding/json" "github.com/bluele/gcache"
"hilo-user/_const/redis_key"
"hilo-user/myerr"
"hilo-user/mylogrus"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
"time" "time"
) )
func GetUserMedalMergeCache(userId mysql.ID) ([]uint32, error) { // 改成lru
bData, err := GetCache(redis_key.GetUserMedalMerge(userId)) var userMedalMergeLru = gcache.New(10000).LRU().Build()
if err != nil {
return nil, myerr.WrapErr(err)
}
res := make([]uint32, 0)
err = json.Unmarshal(bData, &res)
if err != nil {
return nil, myerr.WrapErr(err)
}
return res, nil
}
func GetCache(key string) ([]byte, error) { func GetUserMedalMergeCache(userId mysql.ID) ([]uint32, error) {
data, err := redisCli.GetRedis().Get(context.Background(), key).Bytes() if data, err := userMedalMergeLru.Get(userId); err == nil {
if err != nil { return data.([]uint32), nil
return nil, err
}
return data, nil
}
func SetCache(key string, data interface{}, expire time.Duration) error {
jData, err := json.Marshal(data)
if err != nil {
return err
}
err = redisCli.GetRedis().Set(context.Background(), key, jData, expire).Err()
if err != nil {
mylogrus.MyLog.Errorf("SetCache key:%s, data:%v, err:%s", key, data, err)
return err
} }
return nil return nil, nil
} }
func SetUserMedalMergeCache(userId mysql.ID, data []uint32) error { func SetUserMedalMergeCache(userId mysql.ID, data []uint32) {
err := SetCache(redis_key.GetUserMedalMerge(userId), data, time.Hour*2) _ = userMedalMergeLru.SetWithExpire(userId, data, time.Minute*15)
if err != nil {
mylogrus.MyLog.Errorf("SetUserMedalMerge err:%s", err)
return myerr.WrapErr(err)
}
return nil
} }
package country_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/country_e"
"hilo-user/myerr"
)
type CountryMgrUser struct {
mysql.Entity
Country string
UserId mysql.ID
Role country_e.CountryMgrRole
}
// 获取国家管理人员
func GetCountryMgr(model *domain.Model, userId mysql.ID) (*CountryMgrUser, error) {
cmu := new(CountryMgrUser)
if err := model.Db.WithContext(model.MyContext.Context).Where("user_id = ?", userId).First(&cmu).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return cmu, nil
}
// 更新国家管理人员
func (cmu *CountryMgrUser) UpdateCountryMgr(userId mysql.ID, role country_e.CountryMgrRole, country string) *CountryMgrUser {
cmu.UserId, cmu.Role, cmu.Country = userId, role, country
return cmu
}
// 删除国家管理人员
func (cmu *CountryMgrUser) DeleteCountryMgr() {
cmu.SetDel()
}
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
MsgId uint
}
// 初始化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, 259); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeBirthday1, cp, fmt.Sprintf(GetTranslate(260, lang), users[cp.UserId1].Nick), 0, true, 0, 260); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeBirthday2, cp, fmt.Sprintf(GetTranslate(260, lang), users[cp.UserId2].Nick), 0, true, 0, 260); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, cp, GetTranslate(261, lang), 0, true, 0, 261); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeNormal, cp, GetTranslate(262, lang), 0, true, 0, 262); err != nil {
return err
}
if err := AddCpAnniversary(model, cp_e.AnniversaryItemTypeAnniversary, cp, GetTranslate(263, lang), 0, true, 0, 263); 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, msgId uint) 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,
MsgId: msgId,
}).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, lang string) []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)
}
var userIds = []mysql.ID{relation.UserId1, relation.UserId2}
users, _ := user_m.GetUserMapByIds(model, userIds)
for i, v := range res {
if v.CreatedTime.Equal(v.UpdatedTime) && v.MsgId > 0 {
if v.Type == cp_e.AnniversaryItemTypeBirthday1 {
res[i].Content = fmt.Sprintf(GetTranslate(v.MsgId, lang), users[relation.UserId1].Nick)
} else if v.Type == cp_e.AnniversaryItemTypeBirthday2 {
res[i].Content = fmt.Sprintf(GetTranslate(v.MsgId, lang), users[relation.UserId2].Nick)
} else {
res[i].Content = GetTranslate(v.MsgId, lang)
}
}
}
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, time.Local)
if now > ts {
res = append(res, rows[i])
}
}
return res
}
// 获取cp当天需要提醒的纪念日
func GetUserTodayCpAnniversary(model *domain.Model, cpId mysql.ID, tz *time.Location) []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, tz)
if now > ts {
res = append(res, rows[i])
}
}
return res
}
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, tz *time.Location) int64 {
if tz == nil {
tz = time.Local
}
now := time.Now()
birthday := time.Unix(timestamp, 0)
// 计算今年的生日日期
thisYearBirthday := time.Date(now.Year(), birthday.Month(), birthday.Day(), 0, 0, 0, 0, tz)
// 如果今年的生日还未到,则生日日期为今年的生日日期;否则为明年的生日日期
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("GetCp userId:%d, err:%v", userId, err)
return nil, err
}
return res, nil
}
func GetCpByIds(model *domain.Model, userId1, userId2 uint64) (*CpRelation, error) {
ids := []uint64{userId1, userId2}
res := new(CpRelation)
err := model.DB().Model(CpRelation{}).Where("user_id1 in (?) and user_id2 in (?)", ids, ids).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return res, nil
}
model.Log.Errorf("GetCpByIds userId1:%d, userId2:%d, err:%v", userId1, userId2, 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, sceneUid string) (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
}
if err := rpc.SendCpUpgrade(users[userId1].Nick, users[userId2].Nick, users[userId1].Avatar, users[userId2].Avatar, uint32(cpLevel.Level), sceneUid); 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/myerr"
)
type StatusCp = mysql.Type
const (
Connect StatusCp = 1
Disconnect StatusCp = 2
)
type OldCp struct {
mysql.Entity
//必须保证userId1 > userId2
UserId1 mysql.ID
UserId2 mysql.ID
Score mysql.Num
DayScore mysql.Num
PeriodDay mysql.Str
WeekScore mysql.Num
PeriodWeek mysql.Str
MonthScore mysql.Num
PeriodMonth mysql.Str
Status StatusCp
//中断时长
DisconnectSecond int64
}
func (OldCp) TableName() string {
return "cp"
}
// 获取旧的绑定中的cp
func GetOldConnectCp(model *domain.Model, tmpUserId1 mysql.ID, tmpUserId2 mysql.ID) (*OldCp, error) {
userId1 := tmpUserId1
userId2 := tmpUserId2
if tmpUserId1 < tmpUserId2 {
userId1 = tmpUserId2
userId2 = tmpUserId1
}
cp := OldCp{}
if err := model.Db.Where(&OldCp{
UserId1: userId1,
UserId2: userId2,
Status: Connect,
}).First(&cp).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return &cp, 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).
Where("cp_id not in (1581, 12651, 5171, 9191, 39131, 28801, 181, 35221)").
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
}
// 获取Cp历史分数
func SumCpPoints(model *domain.Model, cpId mysql.ID) mysql.Num {
var score CpDayRank
if err := model.DB().Model(CpDayRank{}).Where("cp_id = ?", cpId).Select("SUM(score) score").Scan(&score).Error; err != nil {
model.Log.Errorf("SumCpPoints fail:%v", err)
}
return score.Score
}
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 package diamond_m
import ( import (
"hilo-user/_const/enum/diamond_e" "fmt"
"hilo-user/domain" "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"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"strconv" "strconv"
"time" "time"
) )
...@@ -36,6 +38,28 @@ type DiamondAccountDetail struct { ...@@ -36,6 +38,28 @@ type DiamondAccountDetail struct {
diamondAccount *DiamondAccount `gorm:"-"` diamondAccount *DiamondAccount `gorm:"-"`
} }
func (DiamondAccountDetail) TableName() string {
month := time.Now().Format("200601")
return fmt.Sprintf("diamond_account_detail_%s", month)
}
// 粉钻详情
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 { type DiamondOperateSet struct {
mysql.Entity mysql.Entity
...@@ -75,7 +99,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -75,7 +99,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
if err = diamondAccount.Db.Where(&DiamondOperateSet{ if err = diamondAccount.Db.Where(&DiamondOperateSet{
Type: operateType, Type: operateType,
Status: mysql.USER, Status: mysql.USER,
DiamondType: diamond_e.DiamondYellow, DiamondType: mysql.DiamondYellow,
}).First(&diamondOperateSet).Error; err != nil { }).First(&diamondOperateSet).Error; err != nil {
return nil, myerr.WrapErr(err) return nil, myerr.WrapErr(err)
} }
...@@ -89,12 +113,13 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -89,12 +113,13 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
var count int64 var count int64
if diamondOperateSet.FrequencyDay == -1 { if diamondOperateSet.FrequencyDay == -1 {
if diamondOperateSet.FrequencyNum != -1 { if diamondOperateSet.FrequencyNum != -1 {
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{ diamondAccount.DB().Table(DiamondAccountDetail{}.TableName()).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId, UserId: diamondAccount.UserId,
OperateType: operateType, OperateType: operateType,
}).Count(&count) }).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) { if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency return nil, bizerr.DiamondFrequency
//return nil, myerr.NewSysError("钻石操作次数多大, userId:" + mysql.IdToStr(diamondAccount.UserId) + " diamondOperateSetId" + mysql.IdToStr(diamondOperateSet.ID))
} }
} }
} else if diamondOperateSet.FrequencyDay == 1 { } else if diamondOperateSet.FrequencyDay == 1 {
...@@ -103,7 +128,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -103,7 +128,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
return nil, myerr.WrapErr(err) return nil, myerr.WrapErr(err)
} }
//一天的次数 //一天的次数
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{ diamondAccount.DB().Table(DiamondAccountDetail{}.TableName()).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId, UserId: diamondAccount.UserId,
OperateType: operateType, OperateType: operateType,
}).Where("created_time >= ? ", beginTime).Count(&count) }).Where("created_time >= ? ", beginTime).Count(&count)
...@@ -111,7 +136,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -111,7 +136,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
return nil, bizerr.DiamondFrequency 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(getZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )") diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1) as n from " + DiamondAccountDetail{}.TableName() + " 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,代表值无效,由参数给与 //-1,代表值无效,由参数给与
...@@ -131,7 +156,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -131,7 +156,7 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
} }
afterNum = diamondAccount.DiamondNum - upateDiamondNum afterNum = diamondAccount.DiamondNum - upateDiamondNum
} else { } else {
return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(diamondOperateSet.AddReduce)) return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(mysql.Type(diamondOperateSet.AddReduce)))
} }
diamondAccountDetail := &DiamondAccountDetail{ diamondAccountDetail := &DiamondAccountDetail{
...@@ -150,3 +175,22 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon ...@@ -150,3 +175,22 @@ func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamon
} }
return diamondAccountDetail, err 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 (
"hilo-user/_const/enum/diamond_e"
"hilo-user/domain"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
)
func CheckEnoughDiamondFrozen(model *domain.Model, userId mysql.ID, diamondNum mysql.Num) (*DiamondAccount, error) {
diamondAccount, err := GetDiamondAccountByUserId(model, userId)
if err != nil {
return nil, err
}
if diamondAccount.DiamondNum < diamondNum {
return nil, bizerr.DiamondNoEnough
}
if diamondAccount.Status == diamond_e.Frozen {
return nil, bizerr.DiamondAccountFrozen
}
return diamondAccount, nil
}
package diamond_m package diamond_m
import ( import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/domain/model"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/mylogrus"
"hilo-user/resource/mysql"
"strconv" "strconv"
) )
func (diamondAccountDetail *DiamondAccountDetail) Persistent() error { func (diamondAccountDetail *DiamondAccountDetail) PersistentNoInTransactional() error {
//fixme: 这里有点奇怪, diamondAccount持久化动作在diamondAccountDetail持久化之后,RowsAffected 就一定是0
txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount) txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
if diamondAccountDetail.diamondAccount.CheckUpdateCondition() { if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition()) txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
...@@ -27,12 +26,15 @@ func (diamondAccountDetail *DiamondAccountDetail) Persistent() error { ...@@ -27,12 +26,15 @@ func (diamondAccountDetail *DiamondAccountDetail) Persistent() error {
return myerr.WrapErr(err) return myerr.WrapErr(err)
} }
if txDiamondAccount.RowsAffected == 0 { if txDiamondAccount.RowsAffected == 0 {
mylogrus.MyLog.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce) diamondAccountDetail.Log.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
return myerr.NewWaring("gorm condition update.RowsAffected = 0") return myerr.NewWaring("gorm condition update.RowsAffected = 0")
} }
//持久化diamondAccountDetail //持久化diamondAccountDetail
if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil { //if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
// return myerr.WrapErr(err)
//}
if err := diamondAccountDetail.DB().Table(diamondAccountDetail.TableName()).Save(diamondAccountDetail).Error; err != nil {
return myerr.WrapErr(err) return myerr.WrapErr(err)
} }
//改变diamondAccount值 //改变diamondAccount值
......
package diamond_m
import "time"
func getZeroTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
package event_m
import (
"gorm.io/gorm"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time"
)
// 离房事件消息
type EventGroupLeave struct {
mysql.Entity
*domain.Model `gorm:"-"`
Proto mysql.Type
Payload []byte
Mark mysql.YesNo
}
// 偏移值
type EventGroupLeaveOffset struct {
mysql.Entity
*domain.Model `gorm:"-"`
MarkOffset mysql.ID
}
// 获取当前偏移值
func GroupLeaveOffset(model *domain.Model) (*EventGroupLeaveOffset, error) {
offset := new(EventGroupLeaveOffset)
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 FetchEventGroupLeave(model *domain.Model, limit int) ([]*EventGroupLeave, *EventGroupLeaveOffset, error) {
offset, err := GroupLeaveOffset(model)
if err != nil {
return nil, nil, err
}
var events []*EventGroupLeave
if err := model.Db.WithContext(model).Model(EventGroupLeave{}).
Where("id > ?", offset.MarkOffset).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchEventGroupLeave fail:%v", err)
return nil, nil, err
}
return events, offset, nil
}
// 标记已完成
func (p *EventGroupLeave) MarkDone() error {
p.Mark = mysql.YES
return p.Db.WithContext(p.Model).Model(EventGroupLeave{}).Where("id = ?", p.ID).Update("mark", p.Mark).Limit(1).Error
}
// 查询过去1小时-5分钟前未mark的事件
// 用来补偿
// 记得加limit
func FetchGroupLeaveUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupLeave, error) {
offset, err := GroupLeaveOffset(model)
if err != nil {
return nil, err
}
t := time.Now().Add(-time.Minute * 5)
lt := t.Add(-time.Hour)
var events []*EventGroupLeave
if err := model.Db.WithContext(model).Model(EventGroupLeave{}).
Where("mark = ?", 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 AddGroupLeaveUnMarkEvent(model *domain.Model, event *EventGroupLeave) error {
return model.Db.WithContext(model).Create(event).Error
}
...@@ -2,10 +2,10 @@ package event_m ...@@ -2,10 +2,10 @@ package event_m
import "hilo-user/domain/model" import "hilo-user/domain/model"
func (p *EventGroupInOffset) Persistence() error { func (p *EventGiftSendOffsetHiloUser) Persistence() error {
return model.Persistent(p.Db, p) return model.Persistent(p.Db, p)
} }
func (p *EventGroupLeaveOffset) Persistence() error { func (p *EventGiftSend) Persistence() error {
return model.Persistent(p.Db, p) return model.Persistent(p.Db, p)
} }
package event_m package event_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time" "time"
) )
// 进房事件消息 // 送礼事件消息
type EventGroupIn struct { type EventGiftSend struct {
mysql.Entity mysql.Entity
*domain.Model `gorm:"-"` *domain.Model `gorm:"-"`
Proto mysql.Type Proto mysql.Type
Payload []byte Payload []byte
Mark mysql.YesNo Mark mysql.YesNo
MarkHiloGroup mysql.YesNo
MarkHiloUser mysql.YesNo
}
func (EventGiftSend) TableName() string {
return "event_gift_send"
} }
// 偏移值 // 偏移值
type EventGroupInOffset struct { type EventGiftSendOffsetHiloUser struct {
mysql.Entity mysql.Entity
*domain.Model `gorm:"-"` *domain.Model `gorm:"-"`
MarkOffset mysql.ID MarkOffset mysql.ID
} }
// 获取当前偏移值 // 获取当前偏移值
func Offset(model *domain.Model) (*EventGroupInOffset, error) { func Offset(model *domain.Model) (*EventGiftSendOffsetHiloUser, error) {
offset := new(EventGroupInOffset) offset := new(EventGiftSendOffsetHiloUser)
if err := model.Db.WithContext(model).First(offset).Error; err != nil { if err := model.Db.WithContext(model).First(offset).Error; err != nil {
if err != gorm.ErrRecordNotFound { if err != gorm.ErrRecordNotFound {
model.Log.Errorf("Offset fail:%v", err) model.Log.Errorf("Offset fail:%v", err)
...@@ -37,41 +44,49 @@ func Offset(model *domain.Model) (*EventGroupInOffset, error) { ...@@ -37,41 +44,49 @@ func Offset(model *domain.Model) (*EventGroupInOffset, error) {
return offset, nil return offset, nil
} }
// 批量获取进房事件 // 批量获取送礼
func FetchEventGroupIn(model *domain.Model, limit int) ([]*EventGroupIn, *EventGroupInOffset, error) { func FetchEventGiftSend(model *domain.Model, limit int) ([]*EventGiftSend, *EventGiftSendOffsetHiloUser, error) {
offset, err := Offset(model) offset, err := Offset(model)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
var events []*EventGroupIn var events []*EventGiftSend
if err := model.Db.WithContext(model).Model(EventGroupIn{}). if err := model.Db.WithContext(model).Model(EventGiftSend{}).
Where("id > ?", offset.MarkOffset). Where("id > ?", offset.MarkOffset).
Order("id asc").Limit(limit).Find(&events).Error; err != nil { Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchEventGroupIn fail:%v", err) model.Log.Errorf("FetchEventGiftSend fail:%v", err)
return nil, nil, err return nil, nil, err
} }
return events, offset, nil return events, offset, nil
} }
// 标记已完成 // 标记已完成
func (p *EventGroupIn) MarkDone() error { func (p *EventGiftSend) MarkDone() error {
p.Mark = mysql.YES p.MarkHiloUser = mysql.YES
return p.Db.WithContext(p.Model).Model(EventGroupIn{}).Where("id = ?", p.ID).Update("mark", p.Mark).Limit(1).Error 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的事件 // 查询过去1小时-5分钟前未mark的事件
// 用来补偿 // 用来补偿
// 记得加limit // 记得加limit
func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupIn, error) { func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGiftSend, error) {
offset, err := Offset(model) offset, err := Offset(model)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t := time.Now().Add(-time.Minute * 5) t := time.Now().Add(-time.Minute * 5)
lt := t.Add(-time.Hour) lt := t.Add(-time.Hour)
var events []*EventGroupIn var events []*EventGiftSend
if err := model.Db.WithContext(model).Model(EventGroupIn{}). if err := model.Db.WithContext(model).Model(EventGiftSend{}).
Where("mark = ?", mysql.NO). Where("mark_hilo_user = ?", mysql.NO).
Where("id <= ?", offset.MarkOffset). Where("id <= ?", offset.MarkOffset).
Where("created_time < ?", t). Where("created_time < ?", t).
Where("created_time > ?", lt). Where("created_time > ?", lt).
...@@ -83,6 +98,6 @@ func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupIn, error) ...@@ -83,6 +98,6 @@ func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupIn, error)
} }
// 补偿加上unmark的event // 补偿加上unmark的event
func AddUnMarkEvent(model *domain.Model, event *EventGroupIn) error { func AddUnMarkEvent(model *domain.Model, event *EventGiftSend) error {
return model.Db.WithContext(model).Create(event).Error return model.Db.WithContext(model).Create(event).Error
} }
package user_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/user_e"
"hilo-user/common"
"hilo-user/domain"
"hilo-user/domain/event/user_ev"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"math/rand"
"strconv"
"time"
)
type GameInfo struct {
Id uint64 `json:"id"`
MgId string `json:"mg_id"`
GameType user_e.GameType `json:"user_type"`
Mode int32 `json:"mode"`
Piece int32 `json:"piece"`
OnOff1 uint8 `json:"on_off1"`
Diamond uint64 `json:"diamond"`
CreateId uint64 `json:"create_id"`
Status uint8 `json:"status"` // '0.未开始 1.游戏中 2.结束'
TxGroupId string `json:"tx_group_id"`
GameRoundId string `json:"user_round_id"`
BattleStartAt uint32 `json:"battle_start_at"`
BattleEndAt uint32 `json:"battle_end_at"`
BattleDuration uint32 `json:"battle_duration"`
AutoMatch uint8 `json:"auto_match"` // 是否开启自动匹配,0否1是
CreatedTime time.Time `json:"created_time"`
UpdatedTime time.Time `json:"updated_time"`
}
type GamePlayer struct {
Id uint64 `json:"id"`
GameId uint64 `json:"user_id"`
UserId uint64 `json:"user_id"`
Status uint8 `json:"status"` // '0.未开始 1.游戏中 2.游戏结束 3.逃跑 4.创建者关闭游戏',
UserCode string `json:"user_code"`
ExternalId string `json:"external_id"`
Rank uint32 `json:"rank"`
IsEscaped uint8 `json:"is_escaped"`
IsAi uint8 `json:"is_ai"`
Role int32 `json:"role"`
Score int32 `json:"score"`
IsWin uint8 `json:"is_win"`
Award uint32 `json:"award"`
Extras string `json:"extras"`
IsManaged uint8 `json:"is_managed"`
EndAt uint32 `json:"end_at"`
SeatIdx int8 `json:"seat_idx"`
Diamond int64 `json:"diamond"` // 黄钻收益,有可能负数
CreatedTime time.Time `json:"created_time"`
UpdatedTime time.Time `json:"updated_time"`
}
type GameAddParam struct {
GameId uint64 `form:"userId"`
GameType user_e.GameType `form:"userType" binding:"required"`
Mode user_e.GameMode `form:"mode" binding:"required"`
Piece int `form:"piece" binding:"required"`
OnOff1 int `form:"onOff1" binding:"required"`
Diamond uint64 `form:"diamond" binding:"required"`
AutoMatch int `form:"autoMatch" binding:"required"`
TxGroupId string `form:"groupId" binding:"required"`
GameCode string `form:"userCode"`
}
type GamePlayerOptLog struct {
Id uint64 `json:"id"`
GameId uint64 `json:"user_id"`
UserId uint64 `json:"user_id"`
Opt uint8 `json:"opt"`
TxGroupId string `json:"tx_group_id"`
CreateAt time.Time `json:"create_at"`
}
type GameSdkReport struct {
Id uint64 `json:"id"`
GameRoundId string `json:"user_round_id"`
TxGroupId string `json:"tx_group_id"`
ReportType string `json:"report_type"`
ReportMsg string `json:"report_msg"`
ExternalId string `json:"external_id"`
SsToken string `json:"ss_token"`
CreateAt time.Time `json:"create_at"`
}
func GetGameInfo(model *domain.Model, userId uint64, txGroupId, roundId string, battleEndAt, status int64) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
if userId != 0 {
db = db.Where("id = ?", userId)
}
if txGroupId != "" {
db = db.Where("tx_group_id = ?", txGroupId)
}
if roundId != "" {
db = db.Where("user_round_id = ?", roundId)
}
if battleEndAt != -1 {
db = db.Where("battle_end_at = ?", battleEndAt)
}
if status != -1 {
db = db.Where("status = ?", status)
}
err := db.First(&res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func GetGamingInfo(model *domain.Model, txGroupId string) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
if txGroupId != "" {
db = db.Where("tx_group_id = ?", txGroupId)
}
err := db.Where("status in (0,1)").First(&res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func Add(model *domain.Model, info *GameInfo) error {
nowTime := time.Now()
info.CreatedTime = nowTime
info.UpdatedTime = nowTime
err := model.Db.Save(info).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func Edit(model *domain.Model, id uint64, para *GameAddParam) error {
if id == 0 {
model.Log.Infof("GameDao Edit id = 0")
return nil
}
err := model.Db.Exec("update user_info set mode=?,piece=?,on_off1=?,diamond=?,auto_match=? where id = ? and battle_start_at = 0",
para.Mode, para.Piece, para.OnOff1, para.Diamond, para.AutoMatch, id).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GameCloseUpdate(model *domain.Model, info *GameInfo) error {
if info.Id == 0 {
model.Log.Infof("GameCloseUpdate Id = 0")
return bizerr.GameNotFound
}
result := model.Db.Exec("update user_info set status=?,battle_end_at=? where id = ? and status != 2",
user_e.GameStatusEnd, time.Now().Unix(), info.Id)
if result.Error != nil {
model.Log.Errorf("GameCloseUpdate info.Id:%v, err:%v", info.Id, result.Error)
return myerr.WrapErr(result.Error)
}
if result.RowsAffected <= 0 {
model.Log.Errorf("GameCloseUpdate info.Id:%v, err:%v", info.Id, result.Error)
return bizerr.GameCloseWrong
}
return nil
}
func GameCloseUpdatePlayer(model *domain.Model, info *GameInfo) error {
if info.Id == 0 {
model.Log.Infof("GameCloseUpdatePlayer Id = 0")
return nil
}
err := model.Db.Exec("update user_player set status=?,end_at=? where user_id = ?", user_e.GamerStatusEnd, time.Now().Unix(), info.Id).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GameStartUpdate(model *domain.Model, info *user_ev.GameStartObject) error {
//var initGameRoundId bool
userInfo := new(GameInfo)
infoKey, err := strconv.Atoi(info.ReportGameInfoKey)
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
}
err = model.Db.Where("id = ?", infoKey).First(&userInfo).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
//if err != gorm.ErrRecordNotFound {
// model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
// return myerr.WrapErr(err)
//}
//userInfo = new(GameInfo)
//err = model.Db.Where("tx_group_id = ? and user_round_id = ''", info.RoomId).First(&userInfo).Error
//if err != nil {
// if err != gorm.ErrRecordNotFound {
// model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
// return myerr.WrapErr(err)
// }
// model.Log.Infof("GameStartUpdate 找不到可以更新的记录 info:%v", info)
// return nil
//}
//initGameRoundId = true
}
if userInfo.Id == 0 {
model.Log.Errorf("GameStartUpdate 记录id为0 userInfo:%v", userInfo)
return myerr.WrapErr(bizerr.GameNotFound)
}
//if initGameRoundId {
// err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? and user_round_id='' limit 1",
// info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
//} else {
// err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? limit 1",
// info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
//}
err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? limit 1",
info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v", err)
return myerr.WrapErr(err)
}
err = model.Db.Exec("update user_player set status=? where user_id = ?", user_e.GamerStatusGaming, userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
// 标记游戏已经开始
func GameStartMark(model *domain.Model, userId mysql.ID) error {
if err := model.DB().Model(GameInfo{}).Where("id = ?", userId).Update("status", user_e.GameStatusGaming).Error; err != nil {
model.Log.Errorf("GameStartMark fail:userId:%v,err:%v", userId, err)
return err
}
return nil
}
// 标记游戏已经结束
func GameEndMark(model *domain.Model, userId mysql.ID) error {
if err := model.DB().Model(GameInfo{}).Where("id = ?", userId).Update("status", user_e.GameStatusEnd).Error; err != nil {
model.Log.Errorf("GameStartMark fail:userId:%v,err:%v", userId, err)
return err
}
return nil
}
func GameSettleUpdate(model *domain.Model, info *user_ev.GameSettleObject) error {
//if info.GameRoundId == "" {
// model.Log.Infof("GameSettleUpdate GameRoundId = 0")
// return nil
//}
infoKey, err := strconv.Atoi(info.ReportGameInfoKey)
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
}
userInfo := new(GameInfo)
err = model.Db.Where("id = ?", infoKey).First(&userInfo).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
result := model.Db.Exec("update user_info set status=?,battle_end_at=?,battle_duration=? where id = ? and status=1",
user_e.GameStatusEnd, info.BattleEndAt, info.BattleDuration, userInfo.Id)
if result.Error != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
if result.RowsAffected <= 0 {
model.Log.Errorf("GameSettleUpdate 修改失败, userInfo.Id:%v", userInfo.Id)
return myerr.WrapErr(bizerr.GameSettleWrong)
}
for _, v := range info.Results {
err = model.Db.Exec("update user_player set status=?,`rank`=?,is_escaped=?,is_ai=?,`role`=?,score=?,is_win=?,"+
"award=?,extras=?,end_at=?,diamond=?,is_managed=? where user_id = ? and external_id = ?",
user_e.GamerStatusEnd, v.Rank, v.IsEscaped, v.IsAi, v.Role, v.Score, v.IsWin, v.Award, v.Extras, info.BattleEndAt,
v.Diamond, v.IsManaged, userInfo.Id, v.Uid).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
}
err = model.Db.Exec("update user_player set status=?,end_at=? where user_id=? and end_at=0",
user_e.GamerStatusEnd, time.Now().Unix(), userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
func GetGamePlayers(model *domain.Model, userId uint64) ([]*GamePlayer, error) {
res := make([]*GamePlayer, 0)
err := model.Db.Where("user_id = ?", userId).Order("created_time").Find(&res).Error
if err != nil {
return nil, err
}
return res, nil
}
func DelGamePlayers(model *domain.Model, userId uint64) error {
if userId <= 0 {
return bizerr.InvalidParameter
}
err := model.Db.Exec("delete from user_player where user_id = ?", userId).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GetGamePlayersMap(model *domain.Model, userId uint64, userExtIds []string) (map[string]*GamePlayer, error) {
list := make([]*GamePlayer, 0, len(userExtIds))
err := model.Db.Where("user_id = ? and external_id in (?)", userId, userExtIds).Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
res := make(map[string]*GamePlayer, 0)
for _, v := range list {
res[v.ExternalId] = v
}
return res, nil
}
func GetGamePlayer(model *domain.Model, userId, userId uint64) (*GamePlayer, error) {
res := new(GamePlayer)
err := model.Db.Where("user_id = ? and user_id = ?", userId, userId).First(res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func SaveGamePlayer(model *domain.Model, info *GamePlayer) error {
err := model.Db.Save(info).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func DelGamePlayer(model *domain.Model, id uint64) error {
result := model.Db.Exec("delete from user_player where id = ? and status=0", id)
if result.Error != nil {
return result.Error
}
if result.RowsAffected <= 0 {
return myerr.WrapErr(bizerr.GameExitWrong)
}
return nil
}
func UpdateGamePlayerExit(model *domain.Model, id uint64) error {
err := model.Db.Exec("update user_player set end_at=? where id = ?", time.Now().Unix(), id).Error
if err != nil {
return err
}
return nil
}
func SaveGameOptLog(model *domain.Model, userId, userId uint64, opt user_e.GameOpt, txGroupId string) error {
defer common.CheckGoPanic()
err := model.Db.Save(&GamePlayerOptLog{GameId: userId, UserId: userId, Opt: uint8(opt), TxGroupId: txGroupId, CreateAt: time.Now()}).Error
if err != nil {
model.Log.Errorf("SaveGameOptLog err:%v", err)
return err
}
return nil
}
func SaveGameSdkReport(model *domain.Model, userRoundId, roomId, reportType, reportMsg, externalId, ssToken string) error {
defer common.CheckGoPanic()
err := model.Db.Save(&GameSdkReport{TxGroupId: roomId, GameRoundId: userRoundId, ReportType: reportType,
ReportMsg: reportMsg, ExternalId: externalId, SsToken: ssToken, CreateAt: time.Now()}).Error
if err != nil {
model.Log.Errorf("SaveGameSdkReport err:%v", err)
return err
}
return nil
}
// 获取一个正在进行游戏的房间id(房间没有密码,没有下注的游戏房间)
func GetGamingTxGroupId(model *domain.Model, userType user_e.GameType) (txGroupId string, err error) {
// 游戏类型,游戏未满人,游戏未开始
infos := make([]*GameInfo, 0)
sql := "select s1.* from (select * from user_info where user_type=? and status=0 and diamond=0 limit 50) s1 left join group_info on s1.tx_group_id=group_info.tx_group_id where group_info.password='' and group_info.tourist_mic=1"
err = model.Db.Raw(sql, userType).Find(&infos).Error
//err = model.Db.Where("status = 0 and user_type = ?", userType).Limit(10).Find(&infos).Error
if err != nil {
return
}
if len(infos) == 0 {
return
}
if len(infos) == 1 {
txGroupId = infos[0].TxGroupId
return
}
// 打乱
rand.Shuffle(len(infos), func(i, j int) {
t := infos[i]
infos[i] = infos[j]
infos[j] = t
})
txGroupId = infos[0].TxGroupId
return
}
// 获取用户在该房间已经加入的未结束的游戏
func GetGamingInfoByUserId(model *domain.Model, userId uint64, txGroupId string) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
err := db.Where("id in (select user_id from user_player where user_id=? and end_at=0) and tx_group_id = ? and status in (0,1)", userId, txGroupId).First(&res).Error
//err := db.Where("status in (0,1)").First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return res, nil
}
package user_m
import (
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/resource/mysql"
"sort"
"time"
)
type StartGamePlayer struct {
TxGroupId mysql.Str // 房间id
GameId mysql.ID // 游戏id
MgId mysql.Str // 游戏sdk id
UserId mysql.ID // 用户id
CreatedTime time.Time // 加入游戏时间
}
// 获取可以开始的游戏
// condition
// 1. 游戏还没开始
// 2. 游戏人数大于等于2个
// 3. 第二个加入的人距离现在已经超过15秒
func GetCanStartGames(model *domain.Model) []GameInfo {
// 1. 游戏还没开始
sql := "SELECT g.tx_group_id,p.user_id,g.mg_id,p.user_id,p.created_time FROM `user_info` g,`user_player` p where p.user_id = g.id AND g.`status` = ?;"
var startGamePlayers []StartGamePlayer
if err := model.DB().Raw(sql, user_e.GameStatusNoStart).Find(&startGamePlayers).Error; err != nil {
model.Log.Errorf("GetCanStartGames fail,sql:%v,err:%v", sql, err)
return nil
}
// userId -> userPlayer
var startGamePlayersMap = make(map[mysql.ID][]StartGamePlayer)
for i, p := range startGamePlayers {
startGamePlayersMap[p.GameId] = append(startGamePlayersMap[p.GameId], startGamePlayers[i])
}
var res []GameInfo
for userId, players := range startGamePlayersMap {
// 2. 游戏人数大于等于2个
if len(players) < 2 {
continue
}
model.Log.Infof("startGamePlayer,userId:%v,player:%+v", userId, players)
// 3. 第二个加入的人距离现在已经超过15秒
sort.Slice(players, func(i, j int) bool {
return players[i].CreatedTime.Before(players[j].CreatedTime)
})
// 客户端15秒,服务端延迟1秒
if time.Now().Sub(players[1].CreatedTime).Seconds() >= 16 {
res = append(res, GameInfo{
Id: userId,
MgId: players[1].MgId,
TxGroupId: players[1].TxGroupId,
})
}
}
return res
}
package user_m
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"hilo-user/_const/enum/robot_e"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/cache/robot_c"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/user_m"
"hilo-user/resource/config"
"hilo-user/resource/mysql"
"hilo-user/rpc"
"time"
)
// 机器人
type GameRobot struct {
mysql.Entity
UserId mysql.ID // 用户id
State robot_e.RobotState // 机器人状态
OpStep robot_e.RobotOp // 当前所在步骤
GroupId string // 群组id
MicIndex int // 麦位
GameUid mysql.ID // 游戏id
MgId string // sdk游戏Id
LastUseTime time.Time // 上次使用的时间
model *domain.Model `gorm:"-"` // db、ctx
Game GameTiny `gorm:"-"` // 需要加入的游戏
User user_m.User `gorm:"-"` // 用户信息
Group *group_m.GroupInfo `gorm:"-"` // 群组信息
Token string `gorm:"-"` // jwt token
Over bool `gorm:"-"` // 是否结束
Err error `gorm:"-"` // 错误日志
// service层的GameOpt
GameOpt func(userId, userId uint64, code, ext, lang, userCode, txGroupId string, opt user_e.GameOpt, seatIdx int8, isAi bool) error `gorm:"-"`
}
// 机器人日志
type GameRobotLog struct {
mysql.Entity
RobotUid mysql.ID
Op robot_e.RobotOp // 机器人操作
DataId string // 房间号 or 麦位 or 游戏id
}
// 标记正在使用中
func (robot *GameRobot) MarkUsing(model *domain.Model) error {
updates := map[string]interface{}{
"state": robot_e.RobotStateUsing,
"last_use_time": time.Now(),
}
return model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
}
// 标记闲置
func (robot *GameRobot) MarkIdle(model *domain.Model) {
updates := map[string]interface{}{
"state": robot_e.RobotStateIdle,
"group_id": "",
"mic_index": -1,
"user_uid": 0,
"mg_id": "",
"op_step": robot_e.RobotOpNone,
}
if err := model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error; err != nil {
robot.model.Log.Errorf("MarkIdle fail:%v", err)
}
}
// 机器人干活了
func (robot *GameRobot) Run() {
robot.model = domain.CreateModelNil()
robot.model.Log = robot.model.Log.WithField("GameRobotRun", robot.ID)
var err error
defer func() {
if err != nil {
robot.model.Log.Errorf("Run fail,robotId:%v,uid:%v,err:%v", robot.ID, robot.UserId, err)
// reset to idle
robot.MarkIdle(robot.model)
robot.Over = true
robot.Err = err
}
}()
// 检查游戏状态
if robot.Game.Status == user_e.GameStatusNoStart { // 未开始
go robot.heartbeat() // 心跳自愈
// 进入游戏流程
switch robot.OpStep {
case robot_e.RobotOpNone:
if err = robot.GroupIn(); err != nil {
return
}
fallthrough
case robot_e.RobotOpGroupIn:
if err = robot.MicIn(); err != nil {
return
}
fallthrough
case robot_e.RobotOpMicIn:
if err = robot.GameIn(); err != nil {
return
}
fallthrough
default:
robot.model.Log.Infof("may in other step:%v", robot.OpStep)
}
} else {
robot.model.Log.Warnf("user status not normal:%v", robot.Game)
}
}
// 进程重启后的机器人自愈
// 如果走过进入游戏了,则继续走心跳逻辑
// 否则,直接走
func (robot *GameRobot) ReRun() {
robot.model = domain.CreateModelNil()
robot.model.Log = robot.model.Log.WithField("GameRobotReRun", robot.ID)
if robot.GameUid > 0 {
go robot.heartbeat()
} else {
robot.Leave("ReRun")
}
}
// 进房
func (robot *GameRobot) GroupIn() error {
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/in"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupId": robot.Game.GroupId,
}
// http to biz
if resp, err := rpc.HttpPutForm(robot.model, url, header, form); err != nil {
return err
} else {
type GroupInResp struct {
Code int `json:"code"`
}
res := new(GroupInResp)
if err = json.Unmarshal(resp, res); err != nil {
return err
} else {
if res.Code != 200 {
return errors.New(fmt.Sprintf("Group In Not 200:%v", res))
} else {
// 复制群组id
robot.GroupId = robot.Game.GroupId
}
}
}
// no error
return robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"group_id": robot.GroupId,
"op_step": robot_e.RobotOpGroupIn,
}
err := txModel.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGroupIn,
DataId: robot.GroupId,
}).Error
})
}
// 上麦
func (robot *GameRobot) MicIn() error {
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/mic/in"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupUuid": robot.GroupId,
"i": "", // 空则随意上一个空位置
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("Mic In fail:%v", err)
return err
} else {
type MicInResp struct {
Code int `json:"code"`
Data struct {
MicIndex int `json:"micIndex"`
} `json:"data"`
}
res := new(MicInResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Mic In json:%v", res))
return err
} else {
if res.Code != 200 || res.Data.MicIndex < 0 {
robot.model.Log.Errorf(fmt.Sprintf("Mic In Not 200:%v,groupId:%v", res, robot.GroupId))
if res.Code == 12008 {
// 群上麦失败,群先做cd,能上麦的情况太多
_ = robot_c.CDMicInGroup(robot.model, robot.GroupId)
}
return errors.New(fmt.Sprintf("Mic In Not 200:%v", res))
} else {
robot.MicIndex = res.Data.MicIndex // 赋值麦位
}
}
}
return robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"mic_index": robot.MicIndex,
"op_step": robot_e.RobotOpMicIn,
}
err := robot.model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpMicIn,
DataId: fmt.Sprintf("%s-%d", robot.GroupId, robot.MicIndex),
}).Error
})
}
// 加入游戏
func (robot *GameRobot) GameIn() error {
if err := robot.GameOpt(robot.UserId, robot.Game.GameUid, robot.User.Code, robot.User.ExternalId, "en", "", robot.GroupId, user_e.GameOptJoin, -1, true); err != nil {
robot.model.Log.Errorf("Game In fail,userId:%v,err:%v", robot.UserId, err)
return err
}
err := robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"user_uid": robot.Game.GameUid,
"mg_id": robot.Game.MgId,
"op_step": robot_e.RobotOpGameIn,
}
err := robot.model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
// 赋值游戏id
robot.GameUid = robot.Game.GameUid
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGameIn,
DataId: fmt.Sprintf("%d", robot.GameUid),
}).Error
})
if err != nil {
return err
}
// GameIn成功之后腾讯云通知
robot.TxGroupInPush()
return nil
}
// 机器人离开
// 下麦+离开房间+退出游戏
func (robot *GameRobot) Leave(reason string) {
// 异常情况会直接leave,保护一下model未赋值
if robot.model == nil {
robot.model = domain.CreateModelNil()
}
robot.model.Log.Infof("robot leave,id:%v,reason:%v", robot.ID, reason)
robot.MicLeave()
robot.GroupLeave()
robot.GameOut()
robot.MarkIdle(robot.model)
}
// 下麦
func (robot *GameRobot) MicLeave() {
// 未上麦
if robot.MicIndex < 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/mic/leave"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupUuid": robot.GroupId,
"i": fmt.Sprintf("%d", robot.MicIndex), //
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("Mic Leave fail:%v", err)
return
} else {
type MicLeaveResp struct {
Code int `json:"code"`
}
res := new(MicLeaveResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Mic Leave json:%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("Mic Leave Not 200:%v", res))
}
}
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpMicLeave,
DataId: fmt.Sprintf("%s-%d", robot.GroupId, robot.MicIndex),
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 离房
func (robot *GameRobot) GroupLeave() {
if len(robot.GroupId) <= 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/leave"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupId": robot.GroupId,
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("GroupLeave fail:%v", err)
return
} else {
type GroupLeaveResp struct {
Code int `json:"code"`
}
res := new(GroupLeaveResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Group Leave json :%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("Group Leave Not 200:%v", res))
}
}
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGroupLeave,
DataId: robot.GroupId,
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 离开游戏
func (robot *GameRobot) GameOut() {
if robot.GameUid <= 0 || len(robot.GroupId) <= 0 {
return
}
if err := robot.GameOpt(robot.UserId, robot.GameUid, robot.User.Code, robot.User.ExternalId, "en", "", robot.GroupId, user_e.GameOptExit, -1, true); err != nil {
robot.model.Log.Errorf("Game Out fail,userId:%v,err:%v", robot.UserId, err)
return
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGameOut,
DataId: fmt.Sprintf("%d", robot.GameUid),
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 腾讯云麦位通知
func (robot *GameRobot) TxGroupInPush() {
if robot.Group == nil || robot.User.ID <= 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/inner/micAllRPush"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"imGroupId": robot.Group.ImGroupId,
"externalId": robot.User.ExternalId,
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("GroupLeave fail:%v", err)
return
} else {
type Resp struct {
Code int `json:"code"`
}
res := new(Resp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("TxGroupInPush json :%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("TxGroupInPush Not 200:%v", res))
}
}
}
}
// 机器人心跳自愈
func (robot *GameRobot) heartbeat() {
// robot.GameUid是mysql/执行完加入游戏才有
userId := robot.GameUid
if userId <= 0 {
// 这里是未加入游戏前的userId
userId = robot.Game.GameUid
}
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
user, err := getGameInfo(robot.model, userId)
if robot.Over || err != nil || user_e.GameStatus(user.Status) == user_e.GameStatusEnd {
robot.Leave("robot over")
return
}
}
}
}
// 根据id获取游戏信息
func getGameInfo(model *domain.Model, userUid mysql.ID) (*GameInfo, error) {
user := new(GameInfo)
err := model.DB().Model(user).Where("id = ?", userUid).First(user).Error
return user, err
}
package user_m
import (
"hilo-user/_const/enum/robot_e"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/cache/robot_c"
"hilo-user/resource/mysql"
"math/rand"
"time"
)
// 游戏结构体
type GameTiny struct {
GameUid mysql.ID
GameType user_e.GameType
GroupId string
MgId int64
Diamond int64
NeedRobots int // 需要机器人数量
Status user_e.GameStatus // 游戏进行状态,1:进行中、0:结束, 心跳实时刷新
UpdatedTime time.Time
}
// 获取需要机器人的游戏
func GetNeedRobotGames(model *domain.Model) ([]GameTiny, error) {
var resGames []GameTiny
// 获取准备开始的游戏
var users []GameTiny
sql := "SELECT user.id as user_uid,user.user_type,user.tx_group_id as group_id,mg_id,user.diamond,user.`status`,user.updated_time FROM user_info user,group_info g " +
"WHERE user.tx_group_id = g.tx_group_id AND user. STATUS = 0 AND user.auto_match = 1 AND user.battle_start_at = 0 AND g.`password` = '' AND g.tourist_mic = 1"
if err := model.DB().Raw(sql).Find(&users).Error; err != nil {
return nil, err
}
now := time.Now()
for _, user := range users {
// 使用user.UpdatedTime(非CreatedTime)去判断8秒,兼容编辑游戏的情况
if now.Sub(user.UpdatedTime).Seconds() <= 8 {
continue
}
// user players
var players []GamePlayer
if err := model.DB().Model(GamePlayer{}).
Where("user_id = ?", user.GameUid).Find(&players).Error; err == nil {
// 没有玩家,属于异常的user
if len(players) <= 0 {
model.Log.Errorf("GetNeedRobotGames no player exits,user:%v,players:%v", user, players)
continue
}
// 玩家大于2个就不需要机器人
if len(players) > 1 {
continue
}
// 机器人进群cd中
if robot_c.IsGroupInCd(model, user.GroupId) {
model.Log.Warnf("IsGroupInCd in cd,user:%v", user)
continue
}
var needRobots = 1 // 一个机器人
resGames = append(resGames, GameTiny{
GameUid: user.GameUid,
GroupId: user.GroupId,
MgId: user.MgId,
NeedRobots: needRobots,
Status: user.Status,
GameType: user.GameType,
Diamond: user.Diamond,
})
} else if err != nil {
model.Log.Errorf("GamePlayer fail:%v", err.Error())
}
}
return resGames, nil
}
// 获取正在使用中的机器人
func GetUsingRobots(model *domain.Model) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("state = ?", robot_e.RobotStateUsing).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取房间中的机器人
func GetRoomRobots(model *domain.Model, txGroupId mysql.Str) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("group_id = ?", txGroupId).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取异常的robot
// state = 0,但是状态没清空
func GetAbnormalRobots(model *domain.Model) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("state = ? AND op_step != 0", robot_e.RobotStateIdle).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取闲置中的机器人
// 并且设置为使用中
func GetSetIdleGameRobots(model *domain.Model, num int) ([]*GameRobot, error) {
if num <= 0 {
model.Log.Warnf("GetSetIdleGameRobots no need robot:%v", num)
return nil, nil
}
var robots []*GameRobot
var canUseRobots []*GameRobot
err := model.Transaction(func(txModel *domain.Model) error {
if err := txModel.Db.WithContext(txModel).Model(GameRobot{}).Where("state = ?", robot_e.RobotStateIdle).Limit(1000).Find(&robots).Error; err != nil {
return err
}
// 打乱1000个空闲的机器人
rand.Shuffle(len(robots), func(i, j int) {
robots[i], robots[j] = robots[j], robots[i]
})
for i, robot := range robots {
// 增加cd逻辑,60秒机器人不复用
if time.Now().Sub(robot.LastUseTime).Seconds() < 60 {
model.Log.Warnf("robot cannot frequency use:%v", robot)
continue
}
if err := robot.MarkUsing(txModel); err != nil {
return err
}
canUseRobots = append(canUseRobots, robots[i])
num--
if num <= 0 {
break
}
}
return nil
})
if err != nil {
model.Log.Errorf("GetIdleGameRobots fail:%v", err)
return nil, err
}
return canUseRobots, nil
}
// 游戏ai启动
func AddAi(model *domain.Model, robots []*GameRobot) {
for _, robot := range robots {
robot.Run() // 一个机器人一个协程
}
}
package groupPower_m package groupPower_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/groupPower_e" "hilo-user/_const/enum/groupPower_e"
"hilo-user/domain"
"hilo-user/domain/model/group_m" "hilo-user/domain/model/group_m"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/resource/mysql"
) )
type GroupPower struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
Name mysql.Str
Status groupPower_e.GroupPowerStatus
}
type GroupPowerUser struct { type GroupPowerUser struct {
mysql.Entity mysql.Entity
*domain.Model `gorm:"-"` *domain.Model `gorm:"-"`
...@@ -25,29 +17,12 @@ type GroupPowerUser struct { ...@@ -25,29 +17,12 @@ type GroupPowerUser struct {
Role groupPower_e.GroupPowerUserRole Role groupPower_e.GroupPowerUserRole
} }
func GetGroupPowerOrErr(model *domain.Model, id uint64) (*GroupPower, error) { type GroupPower struct {
groupPower := GroupPower{} mysql.Entity
if err := model.Db.Model(&GroupPower{}).First(&groupPower, id).Error; err != nil { *domain.Model `gorm:"-"`
return nil, myerr.WrapErr(err) GroupUid mysql.Str
} Name mysql.Str
groupPower.Model = model Status groupPower_e.GroupPowerStatus
return &groupPower, nil
}
//获取用户所在的国家势力信息,不存在则为nil
func GetGroupPowerUserOrNil(model *domain.Model, userId mysql.ID) (*GroupPowerUser, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
UserId: userId,
}).First(&groupPowerUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupPowerUser.Model = model
return &groupPowerUser, nil
} }
// 查询用户加入的国家势力ID及名称(势力绑定的群组的名称) // 查询用户加入的国家势力ID及名称(势力绑定的群组的名称)
...@@ -82,3 +57,28 @@ func GetUserGroupPower(model *domain.Model, userId uint64) (uint64, string, erro ...@@ -82,3 +57,28 @@ func GetUserGroupPower(model *domain.Model, userId uint64) (uint64, string, erro
} }
return gpu.GroupPowerId, powerName, nil return gpu.GroupPowerId, powerName, nil
} }
//获取用户所在的国家势力信息,不存在则为nil
func GetGroupPowerUserOrNil(model *domain.Model, userId mysql.ID) (*GroupPowerUser, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
UserId: userId,
}).First(&groupPowerUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupPowerUser.Model = model
return &groupPowerUser, nil
}
func GetGroupPowerOrErr(model *domain.Model, id uint64) (*GroupPower, error) {
groupPower := GroupPower{}
if err := model.Db.Model(&GroupPower{}).First(&groupPower, id).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupPower.Model = model
return &groupPower, nil
}
package group_m
import (
"context"
"encoding/json"
redisV8 "github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-user/common"
"hilo-user/common/rediskey"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
)
type GroupRoles struct {
mysql.Entity
UserId uint64
ImGroupId string
Role common.GroupRoleType
}
func (this *GroupInfo) TableName() string {
return "group_info"
}
//发言,注意(发言是在麦位上)
type MicUser struct {
model *domain.Model
//群组uuid
GroupUuid string
//麦位
I int
//麦中的人
ExternalId string
//
UserId uint64
//静音 true:静音,false:没有静音
Forbid bool
//上麦的的时间戳
Timestamp int64
}
//记录麦位上有谁。用于
type UserInMic struct {
//群组uuid
GroupUuid string
//麦位
I int
//userId
UserId uint64
}
// 查询用户在IM群组中的角色
func GetRoleInGroup(model *domain.Model, userId uint64, imGroupId string) (uint16, error) {
r := GroupRoles{}
err := model.Db.Where(&GroupRoles{
UserId: userId,
ImGroupId: imGroupId}).First(&r).Error
if err != nil {
if err != gorm.ErrRecordNotFound {
return 0, err
} else {
return 0, nil
}
}
return r.Role, nil
}
func GetByTxGroupId(model *domain.Model, txGroupId string) (*GroupInfo, error) {
if len(txGroupId) <= 0 {
return nil, bizerr.GroupNotFound
}
res := new(GroupInfo)
err := model.Db.Where(&GroupInfo{TxGroupId: txGroupId}).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(bizerr.GroupNotFound)
} else {
return nil, myerr.WrapErr(err)
}
}
return res, nil
}
//获取用户在哪个麦位上。没有不在麦上,则是nil
func GetMicUserByExternalId(model *domain.Model, externalId string) (*MicUser, error) {
if str, err := redisCli.GetRedis().Get(context.Background(), rediskey.GetPrefixGroupUserInMic(externalId)).Result(); err != nil {
if err != redisV8.Nil {
return nil, myerr.WrapErr(err)
} else {
return nil, nil
}
} else {
if userInMic, err := strToUserInMic(str); err != nil {
return nil, err
} else {
return GetMicUser(model, userInMic.GroupUuid, userInMic.I)
}
}
}
//麦位上没人,返回nil
func GetMicUser(model *domain.Model, groupUuid string, i int) (*MicUser, error) {
if i < 1 || i > 30 {
return nil, myerr.NewSysErrorF("麦序不对,不在范围值内 i:%v", i)
}
str, err := redisCli.GetRedis().Get(context.Background(), rediskey.GetPrefixGroupMicUser(groupUuid, i)).Result()
if err != nil {
if err == redisV8.Nil {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
var micUser MicUser
err = json.Unmarshal([]byte(str), &micUser)
if err != nil {
return nil, err
}
return &MicUser{
model: model,
GroupUuid: groupUuid,
I: i,
ExternalId: micUser.ExternalId,
UserId: micUser.UserId,
Forbid: micUser.Forbid,
Timestamp: micUser.Timestamp,
}, nil
}
func strToUserInMic(str string) (UserInMic, error) {
userInMic := UserInMic{}
if err := json.Unmarshal([]byte(str), &userInMic); err != nil {
return UserInMic{}, myerr.WrapErr(err)
}
return userInMic, nil
}
package group_m package group_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/group_e" "hilo-user/_const/enum/group_e"
"hilo-user/domain"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"time" "time"
) )
...@@ -52,12 +52,64 @@ func GetGroupInfo(model *domain.Model, groupId string) (*GroupInfo, error) { ...@@ -52,12 +52,64 @@ func GetGroupInfo(model *domain.Model, groupId string) (*GroupInfo, error) {
return &r, nil return &r, nil
} }
func GetGroupInfoByOwner(model *domain.Model, userId uint64) (*GroupInfo, error) { func FindGroupByOwner(model *domain.Model, ownerId uint64) ([]GroupInfo, error) {
if userId <= 0 { rows := make([]GroupInfo, 0)
err := model.Db.Where(&GroupInfo{Owner: ownerId}).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func ToTxGroupId(model *domain.Model, imGroupId string) (string, error) {
if len(imGroupId) <= 0 {
return "", nil
}
gi, err := GetGroupInfo(model, imGroupId)
if err != nil {
return "", err
}
if gi == nil {
return "", bizerr.GroupNotFound
}
return gi.TxGroupId, nil
}
func ToTxGroupIdMap(model *domain.Model, imGroupIds []string) (map[string]string, error) {
var res = make(map[string]string)
var rows []GroupInfo
if err := model.DB().Model(GroupInfo{}).Where("im_group_id in ?", imGroupIds).Find(&rows).Error; err != nil {
return res, err
}
for _, v := range rows {
res[v.ImGroupId] = v.TxGroupId
}
return res, nil
}
func ToImGroupId(model *domain.Model, txGroupId string) (string, error) {
if len(txGroupId) <= 0 {
return "", nil
}
gi, err := GetInfoByTxGroupId(model, txGroupId)
if err != nil {
return "", err
}
if gi == nil {
return "", bizerr.GroupNotFound
}
return gi.ImGroupId, nil
}
func GetInfoByTxGroupId(model *domain.Model, txGroupId string) (*GroupInfo, error) {
if len(txGroupId) <= 0 {
return nil, bizerr.GroupNotFound return nil, bizerr.GroupNotFound
} }
r := GroupInfo{} r := GroupInfo{}
err := model.Db.Where(&GroupInfo{Owner: userId}).First(&r).Error err := model.Db.Where(&GroupInfo{TxGroupId: txGroupId}).First(&r).Error
if err != nil { if err != nil {
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
return nil, nil return nil, nil
......
package group_m
import (
"hilo-user/domain"
"hilo-user/myerr/bizerr"
)
func ToTxGroupId(model *domain.Model, imGroupId string) (string, error) {
if len(imGroupId) <= 0 {
return "", nil
}
gi, err := GetGroupInfo(model, imGroupId)
if err != nil {
return "", err
}
if gi == nil {
return "", bizerr.GroupNotFound
}
return gi.TxGroupId, nil
}
package group_m
import (
"encoding/json"
"hilo-user/_const/enum/group_e"
"hilo-user/domain"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/user_m"
"hilo-user/rpc"
)
// 信令消息
type GroupSystemMsg struct {
MsgId group_e.TypeSignalMsg `json:"msgId"`
Source string `json:"source"`
Target string `json:"target"`
Content string `json:"content"`
}
type HiloUserInfo struct {
WealthGrade uint32 `json:"wealthGrade"`
CharmGrade uint32 `json:"charmGrade"`
IsVip bool `json:"isVip"`
IsPretty bool `json:"isPretty"`
Medals []uint32 `json:"medals"`
PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称
NobleLevel uint16 `json:"nobleLevel"`
SvipLevel int `json:"svipLevel"`
}
var GetGroupPowerNameByUserId func(model *domain.Model, userId uint64) (uint64, string, error)
//不用返回错误
func GetHiloUserInfo(model *domain.Model, extId string) string {
user, err := user_m.GetUserByExtId(model, extId)
if err != nil {
model.Log.Errorf("extId:%v, err:%+v", extId, err)
return ""
}
wealthGrade, _, err := user_m.GetWealthGrade(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
charmGrade, _, err := user_m.GetCharmGrade(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
isVip, _, err := user_m.IsVip(user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
//
isPretty := user.IsPrettyCode()
//
medals, err := user_m.GetUserMedalMerge(model.Log, model.Db, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
_, powerName, err := GetGroupPowerNameByUserId(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
nobleLevel, err := noble_m.GetNobleLevel(model.Db, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
svip, _ := rpc.GetUserSvip(model, user.ID)
hilo := HiloUserInfo{
WealthGrade: wealthGrade,
CharmGrade: charmGrade,
IsVip: isVip,
IsPretty: isPretty,
Medals: medals,
PowerName: powerName,
NobleLevel: nobleLevel,
SvipLevel: svip.SvipLevel,
}
buf, err := json.Marshal(hilo)
if err != nil {
model.Log.Errorf("hilo:%+v, err:%v", hilo, err)
}
return string(buf)
}
package group_m
import (
"git.hilo.cn/hilo-common/_const/common"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type GroupRoles struct {
mysql.Entity
UserId uint64
ImGroupId string
Role common.GroupRoleType
}
type GroupMember struct {
GroupId string
UserId uint64
}
func (gm *GroupMember) Find(db *gorm.DB) ([]GroupMember, error) {
rows := make([]GroupMember, 0)
if err := db.Where(gm).Order("created_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func GetGroupRoleById(model *domain.Model, imGroupId string, userId uint64) (role common.GroupRoleType, err error) {
role = common.GROUP_VISITOR
roles, _, err := GetRolesInGroup(model, imGroupId)
if err != nil {
return
}
for u, r := range roles {
if u == userId {
role = r
return
}
}
isGroupMember, err := IsGroupMember(model.Db, imGroupId, userId)
if err != nil {
return
}
if isGroupMember {
role = common.GROUP_MEMBER
}
return
}
// 查询群组中所有有角色的成员,由级别高到低、创建时间由早到晚排列
func GetRolesInGroup(model *domain.Model, groupId string) (map[uint64]uint16, []uint64, error) {
data := make([]GroupRoles, 0)
err := model.Db.Where(&GroupRoles{ImGroupId: groupId}).Order("role DESC, created_time").Find(&data).Error
if err != nil {
return nil, nil, err
}
result := make(map[uint64]uint16, 0)
orders := make([]uint64, 0)
for _, i := range data {
orders = append(orders, i.UserId)
result[i.UserId] = i.Role
}
return result, orders, nil
}
func IsGroupMember(db *gorm.DB, groupId string, userId uint64) (bool, error) {
gm := GroupMember{
GroupId: groupId,
UserId: userId,
}
rows, err := gm.Find(db)
if err != nil {
return false, err
}
return len(rows) > 0, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/redis_key/group_k"
"hilo-user/myerr"
"strconv"
"strings"
"time"
)
// 3天
const expireMinute = 60 * 60 * 24 * 3
//获取在房间的用户 返回值:map,key:userId, value:groupUuid
func RoomLivingUserIdFilter(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]string, error) {
userIdSet := map[mysql.ID]struct{}{}
for i, _ := range userIds {
userIdSet[userIds[i]] = struct{}{}
}
key := group_k.GetPrefixGroupRoomLiving()
if err := ClearExpired(model, key, expireMinute); err != nil {
return nil, myerr.WrapErr(err)
}
groupUserIdstrs, err := model.RedisCluster.ZRange(model, key, 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
resultUserSet := map[mysql.ID]string{}
for i, _ := range groupUserIdstrs {
tempGroupUid, userId := analysisMemberStr(groupUserIdstrs[i])
if _, flag := userIdSet[userId]; flag {
resultUserSet[userId] = tempGroupUid
}
}
return resultUserSet, nil
}
func ClearExpired(model *domain.Model, key string, expireSec int64) error {
return model.RedisCluster.ZRemRangeByScore(model, key,
"0", strconv.FormatInt(time.Now().Unix()-expireSec, 10)).Err()
}
func analysisMemberStr(memberStr string) (string, uint64) {
strs := strings.Split(memberStr, "_")
groupUid := strs[0]
userId, err := strconv.ParseUint(strs[1], 10, 64)
if err != nil {
mylogrus.MyLog.Errorf("analysisMemberStr memberStr:%v err:%+v", memberStr, err)
}
return groupUid, userId
}
package invite_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"time"
)
type InviteApply struct {
Id uint64 `json:"id"`
UserId uint64 `json:"user_id"`
NewUserId uint64 `json:"new_user_id"`
Platform string `json:"platform"`
PlatformId string `json:"platform_id"`
RechargeInfo string `json:"recharge_info"`
Status uint8 `json:"status"` // 状态0.未审核1.已通过2.已拒绝
VideoUrl string `json:"video_url"`
Level string `json:"level"`
CreatedTime time.Time `json:"created_time"`
Reason int `json:"reason"` // 1.已申请2.待审核3.已通过4.已拒绝"
SubUserId uint64 `json:"sub_user_id"` // 提交人
}
func CreateInviteApply(model *domain.Model, userId, newUserId, subUserId uint64, platform, platformId, recharge, videoUrl string) error {
err := model.DB().Create(&InviteApply{
UserId: userId, NewUserId: newUserId, Platform: platform, PlatformId: platformId, RechargeInfo: recharge, VideoUrl: videoUrl,
CreatedTime: time.Now(), SubUserId: subUserId}).Error
if err != nil {
model.Log.Errorf("CreateInviteApply err:%v", err)
return err
}
return nil
}
func GetApplyList(model *domain.Model, subUserId uint64, userIds []uint64, pageIndex, pageSize, gType int, beginTime,
endTime time.Time) ([]*InviteApply, int64, error) {
db := model.DB().Model(InviteApply{}).Where("user_id in (?) or sub_user_id = ?", userIds, subUserId).Where("created_time >= ? and created_time <= ?", beginTime, endTime)
switch gType { // 1.已申请2.待审核3.已通过4.已拒绝
case 2:
db = db.Where("`status` = ?", 0)
case 3:
db = db.Where("`status` = ?", 1)
case 4:
db = db.Where("`status` = ?", 2)
}
res := make([]*InviteApply, 0)
var count int64
err := db.Order("id desc").Offset((pageIndex - 1) * pageSize).Find(&res).Limit(-1).Offset(-1).Count(&count).Error
if err != nil {
model.Log.Errorf("GetApplyList err:%v", err)
return nil, 0, err
}
return res, count, nil
}
// 检查被邀请人是否存在
func IsInInviteApply(model *domain.Model, userId mysql.ID) (bool, error) {
var apply InviteApply
if err := model.Db.Model(InviteApply{}).Where("new_user_id = ?", userId).First(&apply).Error; err != nil {
if err != gorm.ErrRecordNotFound {
return false, err
}
return false, nil
}
// err == nil, record exists
return true, nil
}
// 检查被邀请人是否存在
func GetInviteApplyNumByType(model *domain.Model, gType int, beginTime, endTime time.Time, userIds []uint64, subUserId uint64) (int, error) {
var count int64
db := model.Db.Model(InviteApply{}).Where("user_id in (?) or sub_user_id = ?", userIds, subUserId).Where("created_time >= ? and created_time <= ?", beginTime, endTime)
switch gType { // 1.已申请2.待审核3.已通过4.已拒绝
case 2:
db = db.Where("`status` = ?", 0)
case 3:
db = db.Where("`status` = ?", 1)
case 4:
db = db.Where("`status` = ?", 2)
}
if err := db.Count(&count).Error; err != nil {
return 0, err
}
return int(count), nil
}
// 今日已提交次数
func TodayInviteApplyCount(model *domain.Model, userId mysql.ID) (int64, error) {
start, end := utils.DayStartEnd(time.Now())
var count int64
if err := model.Db.Model(InviteApply{}).
Where("user_id = ?", userId).
Where("created_time >= ? and created_time <= ?", start.Format(utils.DATETIME_FORMAT), end.Format(utils.DATETIME_FORMAT)).
Count(&count).Error; err != nil {
return 0, err
}
// err == nil, record exists
return count, nil
}
package msg_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
)
func GetMsgSysRecordInit(model *domain.Model, t uint32, msgSysId uint64) *MsgSysRecord {
return &MsgSysRecord{
Model: model,
Type: t,
Status: mysql.EXIST,
MsgSysId: msgSysId,
}
}
func GetMsgSysRecord(model *domain.Model, msgSysId uint64) (*MsgSysRecord, error) {
msgSysRecord := MsgSysRecord{}
if err := model.Db.Model(&MsgSysRecord{}).Where(&MsgSysRecord{
MsgSysId: msgSysId,
}).First(&msgSysRecord).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
} else {
msgSysRecord.Model = model
return &msgSysRecord, nil
}
}
package msg_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/sdk/emas"
"git.hilo.cn/hilo-common/utils"
"hilo-user/_const/enum/msg_e"
)
type MsgUserRecord struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Type msg_e.MsgUserRecordType
Nick mysql.Str
NickUserId mysql.ID //用户的别名
DiamondIncome mysql.Str
DayNum mysql.Str //多少天
PropertyUrl mysql.Str //道具地址
BeanNum mysql.Str //多少豆子
GroupCode mysql.Str //群组code
}
type MsgSysRecord struct {
mysql.Entity
*domain.Model `gorm:"-"`
//Type msg_m.MsgSysRecordType
Type uint32
Status mysql.LogicDel
MsgSysId mysql.ID
}
//系统消息,用户最后已读的位置
type MsgSysUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
Type msg_e.MsgSysUserType
UserId mysql.ID
MsgSysLastId mysql.ID
}
//删除
func (msgSysRecord *MsgSysRecord) Del() *MsgSysRecord {
msgSysRecord.Status = mysql.DEL
return msgSysRecord
}
type MsgReceive struct {
Type msg_e.MsgReceiveType `json:"type"`
//Timestamp mysql.Timestamp `json:"timestamp"`
}
func NewUserRecord(model *domain.Model, userId mysql.ID, t msg_e.MsgUserRecordType, nick mysql.Str, nickUserId mysql.ID, diamondIncome mysql.Str, dayNum mysql.Str, propertyUrl mysql.Str, beanNum mysql.Str, groupCode mysql.Str) *MsgUserRecord {
return &MsgUserRecord{
Model: model,
UserId: userId,
Type: t,
Nick: nick,
NickUserId: nickUserId,
DiamondIncome: diamondIncome,
DayNum: dayNum,
PropertyUrl: propertyUrl,
BeanNum: beanNum,
GroupCode: groupCode,
}
}
// 发给小助手的消息, 不需要抛出错误
func SendEmasMsgAssistant(model *domain.Model, externalId string, deviceType string) error {
str, _ := utils.ToString(MsgReceive{
Type: msg_e.UserMsgReceiveType,
})
err := emas.SendMsg(externalId, deviceType, str)
if err != nil {
model.Log.Errorf("emas.SendMsg err:%v", err)
}
return nil
}
package msg_m
import (
"hilo-user/domain/model"
"hilo-user/myerr"
)
func (msgUserRecord *MsgUserRecord) Persistent() error {
if err := model.Persistent(msgUserRecord.Db, msgUserRecord); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (msgSysRecord *MsgSysRecord) Persistent() error {
if err := model.Persistent(msgSysRecord.Db, msgSysRecord); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (msgSysUser *MsgSysUser) Persistent() error {
return model.Persistent(msgSysUser.Db, msgSysUser)
}
\ No newline at end of file
package noble_m
import (
"gorm.io/gorm"
"time"
)
const RENEWAL_LIMIT_DAY = 7
type ResNoble struct {
Level uint16
PurchasePrice uint32
RenewalPrice uint32
Duration uint16
PicUrl string
DailyGold uint
RideId uint64 // 赠送的座驾ID
HeaddressId uint64 // 赠送的头饰ID
}
func GetAllConfig(db *gorm.DB) ([]ResNoble, error) {
rows := make([]ResNoble, 0)
err := db.Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func GetAllConfigMap(db *gorm.DB) (map[uint16]ResNoble, error) {
rows, err := GetAllConfig(db)
if err != nil {
return nil, err
}
result := make(map[uint16]ResNoble, 0)
for _, i := range rows {
result[i.Level] = i
}
return result, nil
}
func GetConfigByLevel(db *gorm.DB, level uint16) (ResNoble, error) {
r := ResNoble{}
if err := db.Model(&ResNoble{}).First(&r, level).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return r, nil
} else {
return r, err
}
}
return r, nil
}
// 根据过期时间推算价格
func CalcPrice(cfg ResNoble, endTime time.Time) uint32 {
now := time.Now()
price := cfg.RenewalPrice
if now.After(endTime.AddDate(0, 0, RENEWAL_LIMIT_DAY)) {
price = cfg.PurchasePrice
}
return price
}
package noble_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"time"
)
const (
SRC_APP = 1 // APP
SRC_OPERATION = 2 // 管理后台发放
SRC_H5 = 3 // H5页面
SRC_ACTIVITY = 4 // 活动奖励
RECHARGE_FIRST = 5 // 首次充值
)
type UserNobleLog struct {
mysql.Entity
SenderId uint64
ReceiverId uint64
Level uint16
Money uint32
SrcType uint16
OldEndTime time.Time
NewEndTime time.Time
}
func (ubl *UserNobleLog) Create(db *gorm.DB) error {
return db.Create(ubl).Error
}
package noble_m package noble_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/resource/mysql"
"time" "time"
) )
...@@ -52,22 +53,6 @@ func (ub *UserNoble) Delete(db *gorm.DB) error { ...@@ -52,22 +53,6 @@ func (ub *UserNoble) Delete(db *gorm.DB) error {
return db.Where(ub).Delete(&UserNoble{}).Error return db.Where(ub).Delete(&UserNoble{}).Error
} }
// 查询用户未过期的贵族
func (ub *UserNoble) batchGet(db *gorm.DB, userIds []uint64) (map[uint64][]UserNoble, error) {
rows := make([]UserNoble, 0)
if err := db.Model(ub).Where("end_time>=NOW() AND user_id IN ?", userIds).Order("level DESC").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64][]UserNoble, 0)
for _, i := range rows {
if _, ok := result[i.UserId]; !ok {
result[i.UserId] = make([]UserNoble, 0)
}
result[i.UserId] = append(result[i.UserId], i)
}
return result, nil
}
func FindActiveNoble(db *gorm.DB, userId uint64) (*UserNoble, error) { func FindActiveNoble(db *gorm.DB, userId uint64) (*UserNoble, error) {
ub := UserNoble{ ub := UserNoble{
UserId: userId, UserId: userId,
...@@ -93,3 +78,50 @@ func GetNobleLevel(db *gorm.DB, userId uint64) (uint16, error) { ...@@ -93,3 +78,50 @@ func GetNobleLevel(db *gorm.DB, userId uint64) (uint16, error) {
return noble.Level, nil return noble.Level, nil
} }
} }
func BatchGetNobleLevel(model *domain.Model, userIds []uint64) (map[uint64]uint16, error) {
m, err := BatchGetActiveNoble(model, userIds)
if err != nil {
return nil, err
}
result := make(map[uint64]uint16, 0)
for _, i := range userIds {
result[i] = m[i].Level
}
return result, nil
}
func BatchGetActiveNoble(model *domain.Model, userIds []uint64) (map[uint64]UserNoble, error) {
ub := UserNoble{}
records, err := ub.batchGet(model, userIds)
if err != nil {
return nil, err
}
result := make(map[uint64]UserNoble, 0)
for _, i := range userIds {
if len(records[i]) > 0 {
result[i] = records[i][0]
} else {
result[i] = UserNoble{}
}
}
return result, nil
}
// 查询用户未过期的贵族
func (ub *UserNoble) batchGet(model *domain.Model, userIds []uint64) (map[uint64][]UserNoble, error) {
rows := make([]UserNoble, 0)
if err := model.DB().Model(ub).Where("end_time>=NOW() AND user_id IN ?", userIds).Order("level DESC").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64][]UserNoble, 0)
for _, i := range rows {
if _, ok := result[i.UserId]; !ok {
result[i.UserId] = make([]UserNoble, 0)
}
result[i.UserId] = append(result[i.UserId], i)
}
return result, nil
}
package promotion_m
import "git.hilo.cn/hilo-common/resource/mysql"
// 推广员
type PromotionAgent struct {
mysql.Entity
ManagerId mysql.ID
AgentId mysql.ID
}
// 邀请关系
type PromotionInvite struct {
mysql.Entity
ManagerId mysql.ID
AgentId mysql.ID
Invitee mysql.ID
Platform string
PlatformId string
Reason string
InviteDate string
}
// 邀请关系日志
type PromotionInviteLog struct {
mysql.Entity
AgentId mysql.ID
Invitee mysql.ID
AddReduce mysql.AddReduce
}
package promotion_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
// 获取推广员平台
func GetPromotionPlatforms(model *domain.Model) []string {
return []string{"Falla", "Yalla", "Whisper", "Ahlan", "Mashi", "YoYo", "Yoho", "Echo", "Hawa", "Yalla Ludo", "Hafla",
"Imo", "Ola Party", "ShareChat", "Viya", "Hello Yo", "Bigo Live", "Hago", "Oye Talk", "Tiktok", "Bigo", "Mr7ba"}
}
// 检查是否推广员
func IsPromotionAgent(model *domain.Model, userId mysql.ID) bool {
var promotionAgent PromotionAgent
if err := model.Db.Model(PromotionAgent{}).Where("agent_id = ?", userId).First(&promotionAgent).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("IsPromotionAgent fail:%v", err)
}
} else if promotionAgent.ID > 0 {
return true
}
return false
}
// 检查被邀请人是否存在
func IsPromotionInvitee(model *domain.Model, userId mysql.ID) (bool, error) {
var promotionInvite PromotionInvite
if err := model.Db.Model(PromotionInvite{}).Where("invitee = ?", userId).First(&promotionInvite).Error; err != nil {
if err != gorm.ErrRecordNotFound {
return false, err
}
return false, nil
}
// err == nil, record exists
return true, nil
}
// 检查是否推广经理
func IsPromotionManager(model *domain.Model, userId mysql.ID) bool {
var promotionAgent PromotionAgent
if err := model.Db.Model(PromotionAgent{}).Where("manager_id = ?", userId).First(&promotionAgent).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("IsPromotionManager fail:%v", err)
}
} else if promotionAgent.ID > 0 {
return true
}
return false
}
// 检查是否我的推广经理
func IsMyPromotionManager(model *domain.Model, userId, myUserId mysql.ID) bool {
var promotionAgent PromotionAgent
if err := model.Db.Model(PromotionAgent{}).Where("manager_id = ? and agent_id = ?", userId, myUserId).First(&promotionAgent).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("IsMyPromotionManager fail:%v", err)
}
} else if promotionAgent.ID > 0 {
return true
}
return false
}
// 获取推广经理拥有的所有推广员,包含自己
func GetPromotionManagerAgentList(model *domain.Model, userId mysql.ID) ([]uint64, error) {
uids := make([]uint64, 0)
if err := model.Db.Model(PromotionAgent{}).Where("manager_id = ?", userId).Select("agent_id").
Pluck("agent_id", &uids).Error; err != nil {
model.Log.Errorf("IsPromotionManager fail:%v", err)
return nil, err
}
return uids, nil
}
// 添加推广邀请关系
func AddPromotionInvite(model *domain.Model, managerId, agentId, invitee mysql.ID, platform, platformId, reason, inviteDate string) error {
if err := model.Db.Create(&PromotionInvite{
ManagerId: managerId,
AgentId: agentId,
Invitee: invitee,
Platform: platform,
PlatformId: platformId,
Reason: reason,
InviteDate: inviteDate,
}).Error; err != nil {
return err
}
return addPromotionInviteLog(model, agentId, invitee, mysql.ADD)
}
// 添加推广邀请关系-日志
func addPromotionInviteLog(model *domain.Model, agentId, invitee mysql.ID, addReduce mysql.AddReduce) error {
return model.Db.Create(&PromotionInviteLog{
AgentId: agentId,
Invitee: invitee,
AddReduce: addReduce,
}).Error
}
package recommend_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"time"
)
// 推荐用户送礼
type recommendUserGift struct {
SendUserId mysql.ID
SendUserDiamond mysql.Num
}
var recommendUserGiftKey = "recommendUserGiftKey"
var recommendUserGiftCache = gcache.New(1).LRU().Build()
// 推荐最近送礼的50人,最近12小时赠送礼物大于100k的用户
func SyncPastTop50SendGiftUsers(model *domain.Model) {
limitUserIds, _ := GetBillboardLimitUserList(model)
var res []recommendUserGift
if err := model.DB().Table("gift_operate g").Joins("INNER JOIN user u ON u.id = g.send_user_id").Select("send_user_id,SUM(send_user_diamond) send_user_diamond").
Where("u.avatar <> ''").
Where("g.created_time >= ?", time.Now().Add(-time.Hour*12)).
Where("send_user_id NOT in ?", limitUserIds).
Group("send_user_id").
Having("send_user_diamond > 100000").Order("send_user_diamond DESC").Limit(34).Find(&res).Error; err != nil {
model.Log.Errorf("GetPastTop50SendGiftUsers fail:%v", err)
}
_ = recommendUserGiftCache.Set(recommendUserGiftKey, res)
}
// 只从缓存中拿
func GetPastTop50SendGiftUsers(model *domain.Model) []recommendUserGift {
if data, err := recommendUserGiftCache.Get(recommendUserGiftKey); err == nil {
return data.([]recommendUserGift)
}
return []recommendUserGift{}
}
// 榜单黑名单
func GetBillboardLimitUserList(model *domain.Model) ([]uint64, error) {
var userIds []uint64
if err := model.Db.Table("billboard_limit_user").Select("user_id").Find(&userIds).Error; err != nil {
return nil, err
}
return userIds, nil
}
...@@ -2,10 +2,10 @@ package model ...@@ -2,10 +2,10 @@ package model
import ( import (
"fmt" "fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/resource/mysql"
"time" "time"
) )
......
package res_m package res_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/res_e" "hilo-user/_const/enum/res_e"
"hilo-user/domain"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/resource/mysql"
) )
type ResCountry struct { type ResCountry struct {
...@@ -191,7 +191,7 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) { ...@@ -191,7 +191,7 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) {
if err == nil { if err == nil {
return r.Lang, nil return r.Lang, nil
} else if err == gorm.ErrRecordNotFound { } else if err == gorm.ErrRecordNotFound {
return res_e.DEFAULT_LANG, nil return res_e.DefaultLang, nil
} else { } else {
return "", myerr.WrapErr(err) return "", myerr.WrapErr(err)
} }
......
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type ResGift struct {
mysql.Entity
Name mysql.Str
IconUrl mysql.Str
SvagUrl mysql.Str
MusicUrl mysql.Str
Column uint16
DiamondNum mysql.Num
BeanNum mysql.Num
ReceiveDiamondNum mysql.Num
Second mysql.Num // obsolete
N mysql.Num
GroupBroadcast bool
Cp bool
Together bool
Status mysql.UserYesNo
GiftType mysql.Type
HasGiftText bool
}
// 获取所有的礼物
func FindAllResGiftsMap(model *domain.Model) (map[mysql.ID]ResGift, error) {
res := make(map[mysql.ID]ResGift, 0)
rows := make([]ResGift, 0)
if err := model.DB().Model(ResGift{}).Find(&rows).Error; err != nil {
return nil, err
}
for i, v := range rows {
res[v.ID] = rows[i]
}
return res, nil
}
// 获取礼物
func FindResGift(model *domain.Model, giftId mysql.ID) (*ResGift, error) {
res := new(ResGift)
if err := model.DB().Model(ResGift{}).Where("id = ?", giftId).First(res).Error; err != nil {
return nil, err
}
return res, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
)
type ResHeadwear struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
ReverseEffectUrl mysql.Str
}
//矛盾,项目负责人(产品不接受 商品 同上架分开两个数据结构的模式),又在页面上要求头饰同价格在一起展示,修改。
//目前违背了,ResHeadwearDiamond 作为资源数据,不允许修改的特点。后果在于,对账错误。
type ResHeadwearDiamond struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResHeadwearId mysql.ID
DiamondNum mysql.Num
Second mysql.Num
Status mysql.UserYesNo
}
func InitResHeadwearDiamond(model *domain.Model, resHeadwearId mysql.ID, diamondNum mysql.Num, second mysql.Num) *ResHeadwearDiamond {
return &ResHeadwearDiamond{
Model: model,
ResHeadwearId: resHeadwearId,
DiamondNum: diamondNum,
Second: second,
Status: mysql.NOUSER,
}
}
func GetResHeadwearDiamondByHeadwearIdOrNil(model *domain.Model, resHeadwearId mysql.ID) (*ResHeadwearDiamond, error) {
resHeadwearDiamond := ResHeadwearDiamond{}
if err := model.Db.Model(&ResHeadwearDiamond{}).Where(&ResHeadwearDiamond{
ResHeadwearId: resHeadwearId,
}).First(&resHeadwearDiamond).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resHeadwearDiamond.Model = model
return &resHeadwearDiamond, nil
}
func (resHeadwearDiamond *ResHeadwearDiamond) SetDiamondNum(diamondNum uint32) *ResHeadwearDiamond {
resHeadwearDiamond.DiamondNum = diamondNum
return resHeadwearDiamond
}
func (resHeadwearDiamond *ResHeadwearDiamond) SetSecond(second uint32) *ResHeadwearDiamond {
resHeadwearDiamond.Second = second
return resHeadwearDiamond
}
//设置成未使用
func (resHeadwearDiamond *ResHeadwearDiamond) SetUser() *ResHeadwearDiamond {
resHeadwearDiamond.Status = mysql.USER
return resHeadwearDiamond
}
//设置成未使用
func (resHeadwearDiamond *ResHeadwearDiamond) SetNoUser() *ResHeadwearDiamond {
resHeadwearDiamond.Status = mysql.NOUSER
return resHeadwearDiamond
}
//id获取头饰,不存在则抛异常
func GetHeadwearById(model *domain.Model, id mysql.ID) (*ResHeadwear, error) {
resHeadwear := ResHeadwear{}
if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil {
return nil, myerr.WrapErr(err)
} else {
resHeadwear.Model = model
return &resHeadwear, nil
}
}
//初始化头饰,
func InitHeadwear(model *domain.Model, name string, picUrl string, effectUrl string) *ResHeadwear {
return &ResHeadwear{
Model: model,
Name: name,
PicUrl: picUrl,
EffectUrl: effectUrl,
}
}
//修改头饰
func (resHeadwear *ResHeadwear) EditName(name string) *ResHeadwear {
resHeadwear.Name = name
return resHeadwear
}
func (resHeadwear *ResHeadwear) EditPicUrl(picUrl string) *ResHeadwear {
resHeadwear.PicUrl = picUrl
return resHeadwear
}
func (resHeadwear *ResHeadwear) EditEffectUrl(effectUrl string) *ResHeadwear {
resHeadwear.EffectUrl = effectUrl
return resHeadwear
}
func CheckHeadwearValidById(model *domain.Model, id mysql.ID) (bool, error) {
resHeadwear := ResHeadwear{}
if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return false, nil
} else {
return false, myerr.WrapErr(err)
}
} else {
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
}
package res_m package res_m
import ( import (
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/res_e" "hilo-user/_const/enum/res_e"
"hilo-user/resource/mysql" "time"
) )
type ResMedal struct { type ResMedal struct {
...@@ -41,3 +43,39 @@ func GetUserMedalLevelMap(db *gorm.DB) (map[uint64]uint8, map[uint8][]uint64, er ...@@ -41,3 +43,39 @@ func GetUserMedalLevelMap(db *gorm.DB) (map[uint64]uint8, map[uint8][]uint64, er
} }
return medalTypes, result, nil 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 package res_m
import ( import (
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/res_e" "hilo-user/_const/enum/res_e"
"hilo-user/resource/mysql"
) )
type ResNameplate struct { type ResNameplate struct {
......
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
Area int
}
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
}
package res_m package res_m
import ( import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/res_e" "hilo-user/_const/enum/res_e"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/resource/mysql"
) )
type ResMultiText struct { type ResMultiText struct {
...@@ -27,7 +27,7 @@ func GetResMultiTextBy(db *gorm.DB, msgId uint, Language mysql.Str) (*ResMultiTe ...@@ -27,7 +27,7 @@ func GetResMultiTextBy(db *gorm.DB, msgId uint, Language mysql.Str) (*ResMultiTe
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
if err := db.Where(&ResMultiText{ if err := db.Where(&ResMultiText{
MsgId: msgId, MsgId: msgId,
Language: res_e.DEFAULT_LANG, Language: res_e.DefaultLang,
}).First(&r).Error; err != nil { }).First(&r).Error; err != nil {
return nil, myerr.WrapErr(err) return nil, myerr.WrapErr(err)
} }
......
package tim_m
import (
"encoding/json"
"git.hilo.cn/hilo-common/sdk/tencentyun"
)
type TimHiloInfo struct {
IsVip bool `json:"isVip"`
IsPretty bool `json:"isPretty"`
Medals []uint32 `json:"medals"`
PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称
NobleLevel uint16 `json:"nobleLevel"`
}
func FlushHiloInfo(extId string, isVip bool, isPrettyCode bool, medals []uint32, groupPowerName string, nobleLevel uint16) error {
info := TimHiloInfo{IsVip: isVip, IsPretty: isPrettyCode, Medals: medals, PowerName: groupPowerName, NobleLevel: nobleLevel}
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/user_e"
)
//用户统计
type UserCount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Type user_e.CountType
Num mysql.Num
isAdd bool `gorm:"-"`
isReduce bool `gorm:"-"`
addReduceNum mysql.Num `gorm:"-"`
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/res_m"
"hilo-user/myerr"
"strconv"
"time"
)
//用户头饰
type UserHeadwear struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
HeadwearId mysql.ID
EndTime time.Time
Using headwear_e.UserHeadwearUsing
}
//获取用户头饰,不存在则新建
func GetUserHeadwearOrInit(model *domain.Model, userId mysql.ID, headwearId mysql.ID) (*UserHeadwear, error) {
//检查headwearId是否存在/有效
if flag, err := res_m.CheckHeadwearValidById(model, headwearId); err != nil {
return nil, err
} else {
if flag == false {
return nil, myerr.NewSysError("headwearId: " + strconv.FormatUint(headwearId, 10) + " 无效")
}
}
userHeadwear := UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
HeadwearId: headwearId,
}).First(&userHeadwear).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &UserHeadwear{
Model: model,
UserId: userId,
HeadwearId: headwearId,
EndTime: time.Now(),
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userHeadwear.Model = model
return &userHeadwear, nil
}
//设置为使用中
func (userHeadwear *UserHeadwear) SetUsing() (*UserHeadwear, error) {
if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil {
return nil, err
}
userHeadwear.Using = headwear_e.YesUsing
return userHeadwear, nil
}
//增加结束时间
func (userHeadwear *UserHeadwear) AddEndTime(t headwear_e.UserHeadwearLogOrginType, second uint32, operateUserId mysql.ID) (*UserHeadwear, mysql.ID, error) {
logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, t, headwear_e.AddSecond, &second, nil, operateUserId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
//if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil {
// return nil, logId, err
//}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(second) * time.Second)
return userHeadwear, logId, nil
}
//删除
func (userHeadwear *UserHeadwear) MgrDel(mgrId mysql.ID) (*UserHeadwear, mysql.ID, error) {
logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, headwear_e.Mgr, headwear_e.Del, nil, nil, mgrId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
userHeadwear.SetDel()
return userHeadwear, logId, nil
}
//重置所有的座驾均为不使用状态
func resetAllUserHeadwearNoUsing(model *domain.Model, userId mysql.ID) error {
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
}).UpdateColumn("using", headwear_e.NoUsing).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
//用户装饰日志
type UserHeadwearLog struct {
mysql.Entity
UserId mysql.ID
OperateUserId mysql.ID
HeadwearId mysql.ID
OriginType headwear_e.UserHeadwearLogOrginType
Type headwear_e.UserHeadwearLogType
AddSecond *mysql.Num
UpdateEndTime *time.Time
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
func GetUserHeadwearUsing(model *domain.Model, userId mysql.ID) (*UserHeadwear, error) {
userHeadwear := UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where(&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)
}
}
userHeadwear.Model = model
return &userHeadwear, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/user_e"
"hilo-user/myerr"
)
//用户喜欢
type UserLike struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
LikeUserId mysql.ID
SceneType user_e.UserLikeSceneType
}
type UserLikeOperate struct {
mysql.Entity
UserId mysql.ID
LikeUserId mysql.ID
Type user_e.UserLikeOperateType
SceneType user_e.UserLikeSceneType
}
func AddUserLikeOperate(model *domain.Model, userId mysql.ID, likeUserId mysql.ID, t user_e.UserLikeOperateType, sceneType user_e.UserLikeSceneType) (mysql.ID, error) {
userLikeOperate := UserLikeOperate{
UserId: userId,
LikeUserId: likeUserId,
Type: t,
SceneType: sceneType,
}
if err := model.Db.Create(&userLikeOperate).Error; err != nil {
return 0, myerr.WrapErr(err)
} else {
return userLikeOperate.ID, nil
}
}
func initUserLike(model *domain.Model, userId mysql.ID) *UserLike {
return &UserLike{
Model: model,
UserId: userId,
}
}
/*func GetUserLike(model *domain.Model, userId mysql.ID, likeUserId mysql.ID) (*UserLike, error) {
var userLike UserLike
err := model.Db.Where(&UserLike{
UserId: userId,
LikeUserId: likeUserId,
}).First(&userLike).Error
if err == nil {
return &userLike, nil
} else if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}*/
//喜欢
func (userLike *UserLike) like(likeUserId mysql.ID, sceneType user_e.UserLikeSceneType) (*UserLike, mysql.ID, error) {
err := userLike.Db.Where(&UserLike{
UserId: userLike.UserId,
LikeUserId: likeUserId,
}).First(userLike).Error
//已经喜欢
if err == nil {
return nil, 0, myerr.NewWaring("已经标记喜欢")
} else if err == gorm.ErrRecordNotFound {
userLikeOperateId, err := AddUserLikeOperate(userLike.Model, userLike.UserId, likeUserId, user_e.LikeAdd, sceneType)
if err != nil {
return nil, 0, err
}
userLike.LikeUserId = likeUserId
userLike.SceneType = sceneType
return userLike, userLikeOperateId, nil
} else {
return nil, 0, myerr.WrapErr(err)
}
}
//取消喜欢
func (userLike *UserLike) likeCancel(likeUserId mysql.ID) (*UserLike, error) {
err := userLike.Db.Where(&UserLike{
UserId: userLike.UserId,
LikeUserId: likeUserId,
}).First(userLike).Error
//
if err == nil {
if _, err := AddUserLikeOperate(userLike.Model, userLike.UserId, likeUserId, user_e.LikeCancel, userLike.SceneType); err != nil {
return nil, err
}
userLike.SetDel()
return userLike, nil
} else if err == gorm.ErrRecordNotFound {
return nil, myerr.NewWaring("没有喜欢的记录")
} else {
return nil, myerr.WrapErr(err)
}
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
/**
* 用户活跃分数
**/
type MatchActityUserScore struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Score mysql.Num
Grade mysql.Num
}
// 获取活跃等级
func MGetActiveGrade(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
res := make(map[mysql.ID]mysql.Num)
var rows []MatchActityUserScore
if err := mysql.Db.Model(&MatchActityUserScore{}).Where("user_id in ?", userIds).Find(&rows).Error; err != nil {
model.Log.Errorf("MGetActiveGrade fail:%v", err)
return res, err
}
for _, r := range rows {
res[r.UserId] = r.Grade
}
return res, nil
}
package user_m package user_m
import ( import (
"gorm.io/gorm" "git.hilo.cn/hilo-common/domain"
"hilo-user/_const/enum/match_e" "git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/resource/mysql"
) )
/** /**
...@@ -19,54 +16,15 @@ type MatchCharmUserScore struct { ...@@ -19,54 +16,15 @@ type MatchCharmUserScore struct {
Grade mysql.Num Grade mysql.Num
} }
//获取魅力等级 // 批量获取魅力等级
func GetCharmGrade(model *domain.Model, userId mysql.ID) (uint32, uint32, error) { func MGetCharmGrade(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
var charmUserScore MatchCharmUserScore res := make(map[mysql.ID]mysql.Num)
if err := model.Db.Model(&MatchCharmUserScore{}).Where(&MatchCharmUserScore{ var charmUserScore []*MatchCharmUserScore
UserId: userId, if err := model.Db.Model(&MatchCharmUserScore{}).Where("user_id in ?", userIds).Find(&charmUserScore).Error; err != nil {
}).First(&charmUserScore).Error; err != nil { return res, err
if err == gorm.ErrRecordNotFound {
return 0, 0, nil
} else {
return 0, 0, myerr.WrapErr(err)
} }
for _, r := range charmUserScore {
res[r.UserId] = r.Grade
} }
return charmUserScore.Grade, charmUserScore.Score, nil return res, nil
}
type MatchCharmUserScoreDetail struct {
mysql.Entity
MatchCharmUserScoreId mysql.ID
UserId mysql.ID
BeforeScore mysql.Num
Score mysql.Num
AfterScore mysql.Num
Type match_e.MatchCharmUserScoreDetailType
OrginId mysql.ID
}
func addMatchCharmUserScoreDetail(model *domain.Model, matchCharmUserScoreId mysql.ID, userId mysql.ID, beforeScore mysql.Num, score mysql.Num, t match_e.MatchCharmUserScoreDetailType, orginId mysql.ID) error {
if err := model.Db.Save(&MatchCharmUserScoreDetail{
MatchCharmUserScoreId: matchCharmUserScoreId,
UserId: userId,
BeforeScore: beforeScore,
Score: score,
AfterScore: beforeScore + score,
Type: t,
OrginId: orginId,
}).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
/**
* 获取的分数同等级关系
**/
type MatchCharmSetScoreGrade struct {
mysql.Entity
*domain.Model `gorm:"-"`
MinNum mysql.Num
MaxNum mysql.Num
Grade mysql.Num
} }
package user_m package user_m
import ( import (
"gorm.io/gorm" "git.hilo.cn/hilo-common/domain"
"hilo-user/_const/enum/match_e" "git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/resource/mysql"
) )
/** /**
...@@ -19,52 +16,15 @@ type MatchWealthUserScore struct { ...@@ -19,52 +16,15 @@ type MatchWealthUserScore struct {
Grade mysql.Num Grade mysql.Num
} }
/** // 批量获取财富等级
* 获取的分数同等级关系 func MGetWealthGrade(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
**/ res := make(map[mysql.ID]mysql.Num)
type MatchWealthSetScoreGrade struct { var wealthUserScore []*MatchWealthUserScore
mysql.Entity if err := model.Db.Model(&MatchWealthUserScore{}).Where("user_id in ?", userIds).Find(&wealthUserScore).Error; err != nil {
*domain.Model `gorm:"-"` return res, err
MinNum mysql.Num
MaxNum mysql.Num
Grade mysql.Num
}
type MatchWealthUserScoreDetail struct {
mysql.Entity
MatchWealthUserScoreId mysql.ID
UserId mysql.ID
BeforeScore mysql.Num
Score mysql.Num
AfterScore mysql.Num
Type match_e.MatchWealthUserScoreDetailType
OrginId mysql.ID
}
func addMatchWealthUserScoreDetail(model *domain.Model, matchWealthUserScoreId mysql.ID, userId mysql.ID, beforeScore mysql.Num, score mysql.Num, t match_e.MatchWealthUserScoreDetailType, orginId mysql.ID) error {
if err := model.Db.Save(&MatchWealthUserScoreDetail{
MatchWealthUserScoreId: matchWealthUserScoreId,
UserId: userId,
BeforeScore: beforeScore,
Score: score,
AfterScore: beforeScore + score,
Type: t,
OrginId: orginId,
}).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
//获取财富等级
func GetWealthGrade(model *domain.Model, userId mysql.ID) (uint32, uint32, error) {
var wealthUserScore MatchWealthUserScore
if err := model.Db.Model(&MatchWealthUserScore{}).Where(&MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, 0, nil
} else {
return 0, 0, myerr.WrapErr(err)
} }
for _, r := range wealthUserScore {
res[r.UserId] = r.Grade
} }
return wealthUserScore.Grade, wealthUserScore.Score, nil return res, nil
} }
package user_m package user_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/domain"
"hilo-user/domain/model/common" "hilo-user/domain/model/common"
"hilo-user/domain/model/res_m" "hilo-user/domain/model/res_m"
"hilo-user/resource/mysql"
"time" "time"
) )
...@@ -61,8 +61,8 @@ func GetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userId mysql.ID) ([]ui ...@@ -61,8 +61,8 @@ func GetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userId mysql.ID) ([]ui
} }
} }
} }
logger.Infof("maxGrade %+v", maxGrades) //logger.Infof("maxGrade %+v", maxGrades)
logger.Infof("maxMedalIds %+v", maxMedalIds) //logger.Infof("maxMedalIds %+v", maxMedalIds)
mIds := result mIds := result
result = make([]uint32, 0) result = make([]uint32, 0)
...@@ -89,3 +89,15 @@ func GetUserMedal(db *gorm.DB, userId mysql.ID) ([]uint32, error) { ...@@ -89,3 +89,15 @@ func GetUserMedal(db *gorm.DB, userId mysql.ID) ([]uint32, error) {
} }
return result, nil 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
}
package user_m package user_m
import ( import (
"hilo-user/domain" "git.hilo.cn/hilo-common/domain"
"hilo-user/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"time" "time"
) )
......
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/property_e"
"hilo-user/myerr"
"time"
)
//用户道具
type UserProperty struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
PropertyId mysql.ID
EndTime time.Time
Using property_e.UserPropertyUsing
}
func GetUserPropertyOrInit(model *domain.Model, userId mysql.ID, propertyId mysql.ID) (*UserProperty, error) {
userProperty := UserProperty{}
if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{
UserId: userId,
PropertyId: propertyId,
}).First(&userProperty).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &UserProperty{
Model: model,
UserId: userId,
PropertyId: propertyId,
EndTime: time.Now(),
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userProperty.Model = model
return &userProperty, nil
}
//设置为使用中
func (userProperty *UserProperty) SetUsing() (*UserProperty, error) {
if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil {
return nil, err
}
userProperty.Using = property_e.YesUsing
return userProperty, nil
}
//增加结束时间
func (userProperty *UserProperty) AddEndTime(t property_e.UserPropertyLogOrginType, second uint32, operateUserId mysql.ID) (*UserProperty, mysql.ID, error) {
logId, err := addUserPropertyLog(userProperty.Model, userProperty.UserId, userProperty.PropertyId, t, property_e.AddSecond, &second, nil, operateUserId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
//if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil {
// return nil, logId, err
//}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(second) * time.Second)
return userProperty, logId, nil
}
//重置所有的座驾均为不使用状态
func ResetAllUserPropertyNoUsing(model *domain.Model, userId mysql.ID) error {
if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{
UserId: userId,
}).UpdateColumn("using", property_e.NoUsing).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
//增加修改日志
func addUserPropertyLog(model *domain.Model, userId mysql.ID, propertyId mysql.ID, originType property_e.UserPropertyLogOrginType, t property_e.UserPropertyLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userPropertyLog := UserPropertyLog{
UserId: userId,
OperateUserId: operateUserId,
PropertyId: propertyId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userPropertyLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userPropertyLog.ID, nil
}
func RemoveUserProperty(model *domain.Model, userId mysql.ID, propertyId mysql.ID) error {
return model.Db.Where("user_id = ? AND property_id = ?", userId, propertyId).Delete(&UserProperty{}).Error
}
//用户道具日志
type UserPropertyLog struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
OperateUserId mysql.ID
PropertyId mysql.ID
OriginType property_e.UserPropertyLogOrginType
Type property_e.UserPropertyLogType
AddSecond *mysql.Num
UpdateEndTime *time.Time
}
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/_const/common"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
"time"
)
type Relation struct {
// 永恒之心值
HeartValue uint32 `json:"heartValue"`
// 永恒之心的最大值(0代表没有永恒之心,即没有相互关注)
HeartValueMax uint32 `json:"heartValueMax"`
// 成长关系建立的时间(天数)
MeetDays uint `json:"meetDays"`
}
//用户成长关系
type UserRelation struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId_1 mysql.ID
UserId_2 mysql.ID
HeartValue uint32
}
// 查询成长关系
func GetRelation(model *domain.Model, userId1, userId2 mysql.ID) (Relation, error) {
result := Relation{0, 0, 0}
if userId1 == userId2 {
return result, nil
}
// 保证uid小的在前面
if userId1 > userId2 {
userId1, userId2 = userId2, userId1
}
rel := UserRelation{UserId_1: userId1, UserId_2: userId2, HeartValue: 0}
if err := model.DB().Model(&UserRelation{}).Where(&UserRelation{
UserId_1: userId1,
UserId_2: userId2,
}).First(&rel).Error; err != nil {
if err == gorm.ErrRecordNotFound {
// 没有成长关系的情况
return result, nil
} else {
return result, myerr.WrapErr(err)
}
}
result.HeartValueMax = common.HEART_VALUE_MAX
result.HeartValue = rel.HeartValue
if result.HeartValue > common.HEART_VALUE_MAX {
result.HeartValue = common.HEART_VALUE_MAX
}
d := uint(time.Since(rel.CreatedTime).Hours() / 24)
if d < 0 {
d = 0
}
result.MeetDays = d
return result, nil
}
// 批量查询成长关系
func BatchGetRelations(model *domain.Model, userId mysql.ID, others []mysql.ID) (map[mysql.ID]Relation, error) {
smaller := make([]mysql.ID, 0)
greater := make([]mysql.ID, 0)
for _, i := range others {
if i < userId {
smaller = append(smaller, i)
} else if i > userId {
greater = append(greater, i)
}
}
rows := make([]UserRelation, 0)
result := make(map[mysql.ID]Relation, 0)
var err error
if len(greater) > 0 {
if err = model.DB().Model(&UserRelation{}).Where("user_id_1 = ? AND user_id_2 IN ?", userId, greater).Find(&rows).Error; err != nil {
return result, err
}
}
for _, i := range rows {
if i.HeartValue > common.HEART_VALUE_MAX {
i.HeartValue = common.HEART_VALUE_MAX
}
d := uint(time.Since(i.CreatedTime).Hours() / 24)
if d < 0 {
d = 0
}
result[i.UserId_2] = Relation{HeartValue: i.HeartValue, HeartValueMax: common.HEART_VALUE_MAX, MeetDays: d}
}
rows = make([]UserRelation, 0)
if len(smaller) > 0 {
if err = model.DB().Model(&UserRelation{}).Where("user_id_1 IN ? AND user_id_2 = ?", smaller, userId).Find(&rows).Error; err != nil {
return result, err
}
}
for _, i := range rows {
if i.HeartValue > common.HEART_VALUE_MAX {
i.HeartValue = common.HEART_VALUE_MAX
}
d := uint(time.Since(i.CreatedTime).Hours() / 24)
if d < 0 {
d = 0
}
result[i.UserId_1] = Relation{HeartValue: i.HeartValue, HeartValueMax: common.HEART_VALUE_MAX, MeetDays: d}
}
// 补上没有成长关系的人
for _, u := range others {
if _, exists := result[u]; !exists {
result[u] = Relation{0, 0, 0}
}
}
return result, err
}
package user_m package user_m
import "hilo-user/domain/model"
func (userHeadwear *UserHeadwear) Persistent() error {
return model.Persistent(userHeadwear.Db, userHeadwear)
}
func (userProperty *UserProperty) Persistent() error {
return model.Persistent(userProperty.Db, userProperty)
}
func (userPropertyLog *UserPropertyLog) Persistent() error {
return model.Persistent(userPropertyLog.Db, userPropertyLog)
}
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(userIds []uint64) (map[uint64]bool, error) {
if len(userIds) == 0 {
return map[uint64]bool{}, nil
}
var superManagers []SuperManager
if err := mysql.Db.Model(&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
}
package user_m package user_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/user_e" "hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"hilo-user/resource/mysql" "time"
) )
//用户信息 //用户信息
...@@ -51,6 +52,11 @@ func (u User) IsPrettyCode() bool { ...@@ -51,6 +52,11 @@ func (u User) IsPrettyCode() bool {
return u.Code != u.OriginCode return u.Code != u.OriginCode
} }
// 七天内注册
func (u User) IsNew() bool {
return time.Now().Sub(u.CreatedTime).Hours() < 24*7
}
//获取用户 //获取用户
func GetUser(model *domain.Model, id mysql.ID) (*User, error) { func GetUser(model *domain.Model, id mysql.ID) (*User, error) {
var user User var user User
...@@ -106,3 +112,71 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) { ...@@ -106,3 +112,71 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) {
user.Model = model user.Model = model
return &user, nil 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
}
//获取用户的国家,和所属的区域(是否阿语区)
func GetUserCountryArea(model *domain.Model, userId mysql.ID) (string, int, error) {
type info struct {
Name string
Area int
}
res := new(info)
if err := model.Db.WithContext(model.Context).Raw("select name, area from res_country where name = (select country from user where id = ?)", userId).First(&res).Error; err != nil {
return "", 0, myerr.WrapErr(err)
}
return res.Name, res.Area, nil
}
//获取用户的国家所属的区域(是否阿语区)
func GetUserAreaMap(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]int, error) {
type info struct {
Id mysql.ID
Area int
}
rows := make([]*info, 0)
sql := "select user.id, rc.area from user left join res_country rc on user.country = rc.name where user.id in (?);"
if err := model.DB().Raw(sql, userIds).Scan(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
res := make(map[mysql.ID]int)
for _, v := range rows {
res[v.Id] = v.Area
}
return res, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"time"
)
type UserBindInfo struct {
UserId uint64 `json:"user_id"`
Phone string `json:"phone"`
PhoneCountry string `json:"phone_country"`
Pwd string `json:"pwd"`
AreaCode string `json:"area_code"`
Icon string `json:"icon"`
CreateAt time.Time `json:"create_at"`
UpdateAt time.Time `json:"update_at"`
}
func (*UserBindInfo) TableName() string {
return "user_bind_info"
}
type UserPhoneInfo struct {
Phone string `json:"phone"`
PhoneCountry string `json:"phoneCountry"`
AreaCode string `json:"areaCode"`
Icon string `json:"icon"`
}
// 获取用户手机号绑定信息
func GetUserBindInfoByUserId(model *domain.Model, userId uint64) (*UserBindInfo, error) {
res := new(UserBindInfo)
err := model.DB().Where(&UserBindInfo{UserId: userId}).First(&res).Error
if err != nil {
return nil, err
}
return res, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
"hilo-user/myerr"
)
type UserOauth struct {
UserId uint64 `json:"user_id"`
ThirdPartyId string `json:"third_party_id"`
ThirdPartyType int8 `json:"third_party_type"`
}
func (*UserOauth) TableName() string {
return "user_oauth"
}
// 根据id获取第三方登录信息
func GetUserOauthByUserId(model *domain.Model, userId uint64, thirdType uint8) ([]*UserOauth, error) {
res := make([]*UserOauth, 0)
db := model.DB().Where(&UserOauth{UserId: userId})
if thirdType > 0 {
db = db.Where(&UserOauth{ThirdPartyType: int8(thirdType)})
}
err := db.Find(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return res, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
)
type UserTradeUnion struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
MatchNotification mysql.OpenClose
AgentId mysql.ID
StarchatId mysql.ID
Avatar string
}
func GetUserTradeUnion(userId mysql.ID) (*UserTradeUnion, error) {
var userTradeUnion UserTradeUnion
if err := mysql.Db.Where(UserTradeUnion{
UserId: userId,
}).First(&userTradeUnion).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return &userTradeUnion, nil
}
type AgentMgr struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
AgentId mysql.ID
}
func IsAgent(userId uint64) bool {
data := AgentMgr{}
return mysql.Db.Where(&AgentMgr{UserId: userId}).First(&data).Error == nil
}
package user_m package user_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-user/_const/enum/user_e" "hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time" "time"
) )
...@@ -43,3 +43,24 @@ func GetVip(db *gorm.DB, userId uint64) (*UserVip, error) { ...@@ -43,3 +43,24 @@ func GetVip(db *gorm.DB, userId uint64) (*UserVip, error) {
} }
return nil, nil 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 visit_m
import "hilo-user/domain/model"
func (userVisit *UserVisit) Persistent() error {
return model.Persistent(userVisit.Db, userVisit)
}
package visit_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/myerr"
)
type UserVisit struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
VisitUserId mysql.ID
N mysql.Num
}
func GetVisitInstanceOrInit(model *domain.Model, userId mysql.ID, visitUserId mysql.ID) (*UserVisit, error) {
var userVisit UserVisit
if err := model.Db.Where(&UserVisit{
UserId: userId,
VisitUserId: visitUserId,
}).FirstOrInit(&userVisit, UserVisit{
UserId: userId,
VisitUserId: visitUserId,
N: 0,
}).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userVisit.Model = model
return &userVisit, nil
}
func (userVisit *UserVisit) UserVisitAdd() *UserVisit {
userVisit.N = userVisit.N + 1
return userVisit
}
package cp_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/cp_m"
"time"
)
type CpService struct {
svc *domain.Service
}
func NewCpService(myContext *mycontext.MyContext) *CpService {
svc := domain.CreateService(myContext)
return &CpService{svc}
}
// 获取用户cp信息
func (s *CpService) GetUserCp(userId uint64, lang string) (*user_cv.CvCp, error) {
var model = domain.CreateModelContext(s.svc.MyContext)
cpLevel := cp_e.CpLevel0
cpRelation, exists := cp_m.GetCpRelation(model, userId)
if !exists {
return nil, nil
}
var myPrivilegeList []user_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 nil, err
}
privilegeList := cp_cv.CopyCpLevelPrivilegeList(level.Level, "en")
for i, v := range privilegeList {
if v.CanSwitch {
privilegeList[i].UserSwitch = userPrivileges[userId][v.Type]
}
}
// 我的特权,有开关并且打开才返回
for _, v := range privilegeList {
if !v.CanSwitch {
myPrivilegeList = append(myPrivilegeList, user_cv.CvPrivilege{Type: v.Type})
} else if v.UserSwitch {
myPrivilegeList = append(myPrivilegeList, user_cv.CvPrivilege{Type: v.Type})
}
}
userBases, err := user_cv.GetUserBaseForCpMap([]uint64{cpUserId})
if err != nil {
return nil, err
}
// 返回值
title := cp_cv.GetTranslate(237, lang)
if msgId, ok := cp_e.CpLevelTitle[level.Level]; ok {
title = cp_cv.GetTranslate(msgId, lang)
}
var oldScore uint32
if oldCp, _ := cp_m.GetOldConnectCp(model, cpRelation.UserId1, cpRelation.UserId2); oldCp != nil {
oldScore = uint32(oldCp.Score)
}
response := &user_cv.CvCp{
CpUserInfo: userBases[cpUserId],
CpLevel: user_cv.CvCpLevel{
Level: cpLevel,
Points: oldScore + cp_m.SumCpPoints(model, cpRelation.Id), // 历史分数
Title: title,
},
MyPrivilegeList: myPrivilegeList,
CpDays: int(time.Now().Sub(cpRelation.CreatedTime).Hours()/24) + 1,
CreatedUnix: cpRelation.CreatedTime.Unix(),
}
return response, 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,且cp关系存在
cpRelation, err := cp_m.GetCpByIds(model, myUserId, userRec.ID)
if err != nil {
return err
}
if cpRelation.Id == 0 {
model.Log.Errorf("CancelCpRelation cp关系不存在 id1:%v, id2:%v", myUserId, userRec.ID)
return myerr.WrapErr(bizerr.InvalidParameter)
}
//// 自己没有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
// 送礼增加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, sendGiftEvent.SceneUid); 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
// })
//}
// 漏掉加分数的送礼记录,补上cp增加分数
// 送礼增加cp等级
// 送礼增加cp排行榜
//func CompensateCpScore() {
// if !config.IsMaster() {
// return
// }
// model := domain.CreateModelNil()
// num, err := redisCli.IncrNumExpire("scirpt:compensateCpScore", 1, time.Hour*999)
// if err != nil {
// model.Log.Errorf("CompensateCpScore err:%v", err)
// }
// if num > 1 {
// model.Log.Errorf("CompensateCpScore 执行过了,退出")
// return
// }
// // 查找需要补分的送礼记录
// type GiftOperate struct {
// Id uint64 `json:"id"`
// ResGiftId uint64 `json:"res_gift_id"`
// GiftN int32 `json:"gift_n"`
// SendUserId uint64 `json:"send_user_id"`
// ReceiveUserId uint64 `json:"receive_user_id"`
// SendUserDiamond uint32 `json:"send_user_diamond"`
// SceneType int8 `json:"scene_type"`
// SceneUid string `json:"scene_uid"`
// CreatedTime time.Time `json:"created_time"`
// }
// rows := make([]*GiftOperate, 0)
// err = model.DB().Model(GiftOperate{}).
// Where("created_time < ?", "2023-06-22 11:20:15").
// Where("res_gift_id in (?)",
// []int{3561, 3571, 3581, 3591, 3601, 3611, 3621, 3631, 3641, 3651, 3661, 3671, 3681, 3691, 3701, 3711}).
// Find(&rows).Error
// if err != nil {
// model.Log.Errorf("CompensateCpScore err:%v", err)
// return
// }
// model.Log.Infof("CompensateCpScore len(rows):%v", len(rows))
//
// for idx, r := range rows {
// diamonds := r.SendUserDiamond
// // 有cp关系
// if cpRelation, exits := cp_m.GetCpRelationPair(model, r.SendUserId, r.ReceiveUserId); exits {
// if err := cp_m.AddCpLevelPoints(model, cpRelation, diamonds, gift_e.GiftOperateSceneType(r.SceneType), r.SceneUid); err != nil {
// model.Log.Errorf("CompensateCpScore AddCpLevelPoints fail:%v", err)
// return
// }
// if err := cp_m.AddCpDayRank(model, cpRelation, diamonds); err != nil {
// model.Log.Errorf("CompensateCpScore AddCpDayRank fail:%v", err)
// return
// }
// // 检查最新的等级
// 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("CompensateCpScore 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 = r.CreatedTime.Format("2006-01-02"), r.CreatedTime.Format("2006-01-02")
// cpAchievementType = cp_e.CpAchievementDayRank
// case "week":
// beginDate = now.With(r.CreatedTime).BeginningOfWeek().Format("2006-01-02")
// endDate = now.With(r.CreatedTime).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("CompensateCpScore UpdateCpAchievement fail:%v", err)
// }
// }
// }
// }
// model.Log.Infof("CompensateCpScore idx:%v", idx)
// if idx%1000 == 0 {
// time.Sleep(time.Millisecond * 100)
// }
// }
//
// model.Log.Infof("CompensateCpScore 补偿完毕")
//}
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
})
}
package event_s
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"github.com/pkg/errors"
"hilo-user/_const/enum/msg_e"
"hilo-user/_const/enum/res_e"
"hilo-user/domain/event/user_ev"
"hilo-user/domain/model/msg_m"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
)
func EventInit() {
UserBagSendEvent()
//CpGiftEvent()
CpSpaceVisitEvent()
}
func UserBagSendEvent() {
user_ev.AddUserBagSendAsync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*user_ev.UserBagSendEvent)
if !ok {
return errors.New("AddUserBagSendAsync param fail")
}
if e.ResType != res_e.ResUserBagGift {
return nil
}
user, err := user_m.GetUser(model, e.UserId)
if err != nil {
return err
}
gift, err := res_m.FindResGift(model, e.ResId)
if err != nil {
return err
}
if err := msg_m.NewUserRecord(model, e.UserId, msg_e.AddUserBag,
gift.Name, 0, "", fmt.Sprintf("%d", e.Day),
"", "", "").Persistent(); err != nil {
model.Log.Errorf("NewUserRecord fail")
} else {
msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
}
return nil
})
}
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
})
}
package headwear_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"time"
)
type HeadwearService struct {
svc *domain.Service
}
func NewHeadwearService(myContext *mycontext.MyContext) *HeadwearService {
svc := domain.CreateService(myContext)
return &HeadwearService{svc}
}
// 下发头饰
func (s *HeadwearService) SendHeadwear(receiverUserId mysql.ID, headdressId mysql.ID, days int) error {
var model = domain.CreateModelContext(s.svc.MyContext)
// 头饰增加
receiveHeadwearDuration := uint32(days) * 3600 * 24
if headdressId <= 0 {
return bizerr.InvalidParameter
}
userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, headdressId)
if err != nil {
return err
}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second)
if err := userHeadwear.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if _, err = addUserHeadwearLog(model, receiverUserId, headdressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil {
model.Log.Error(err)
}
return err
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := user_m.UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
package noble_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/headwear_e"
"hilo-user/_const/enum/msg_e"
"hilo-user/_const/enum/property_e"
"hilo-user/domain/model/msg_m"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"strconv"
"time"
)
type NobleService struct {
svc *domain.Service
}
func NewNobleService(myContext *mycontext.MyContext) *NobleService {
svc := domain.CreateService(myContext)
return &NobleService{svc}
}
// 下发贵族
func (s *NobleService) SendNoble(receiverUserId mysql.ID, level uint16, days int) error {
model := domain.CreateModelContext(s.svc.MyContext)
if level <= 0 {
return bizerr.InvalidParameter
}
cfg, err := noble_m.GetConfigByLevel(model.Db, level)
if err != nil {
return err
}
if cfg.PurchasePrice <= 0 || cfg.RenewalPrice <= 0 {
return bizerr.InvalidParameter
}
n := noble_m.UserNoble{UserId: receiverUserId, Level: level}
records, err := n.FindAll(model.Db)
if err != nil {
return err
}
if len(records) > 1 {
// DB表结构决定了不可能发生
return bizerr.IncorrectState
}
if len(records) <= 0 {
// 新增贵族
endTime := time.Now().AddDate(0, 0, int(days))
n = noble_m.UserNoble{UserId: receiverUserId, Level: level, EndTime: endTime}
err = n.Create(model.Db)
if err != nil {
return err
}
nbl := noble_m.UserNobleLog{
SenderId: 0,
ReceiverId: receiverUserId,
Level: level,
Money: 0,
SrcType: noble_m.SRC_APP,
NewEndTime: endTime,
}
err = nbl.Create(model.Db)
if err != nil {
return err
}
} else {
// 延长贵族
n = records[0]
now := time.Now()
endTime := n.EndTime.AddDate(0, 0, int(days))
if now.After(n.EndTime) {
endTime = now.AddDate(0, 0, int(days))
}
nn := noble_m.UserNoble{
Entity: mysql.Entity{ID: n.ID, UpdatedTime: n.UpdatedTime},
}
af, err := nn.UpdateEndTime(model.Db, endTime)
if err != nil {
return err
}
if af <= 0 {
return bizerr.TransactionFailed
}
nbl := noble_m.UserNobleLog{
SenderId: 0,
ReceiverId: receiverUserId,
Level: level,
Money: 0,
SrcType: noble_m.SRC_APP,
OldEndTime: n.EndTime,
NewEndTime: endTime,
}
err = nbl.Create(model.Db)
if err != nil {
return err
}
}
// 头饰增加
receiveHeadwearDuration := uint32(days) * 3600 * 24
if cfg.HeaddressId != 0 {
userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, cfg.HeaddressId)
if err != nil {
return err
}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second)
if err := userHeadwear.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if _, err := addUserHeadwearLog(model, receiverUserId, cfg.HeaddressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil {
model.Log.Error(err)
}
}
// 增加座驾
receivePropertyDuration := uint32(days) * 3600 * 24
if cfg.RideId != 0 {
userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, cfg.RideId)
if err != nil {
return err
}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second)
if err := userProperty.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if err := (&user_m.UserPropertyLog{
Model: model,
UserId: receiverUserId,
PropertyId: cfg.RideId,
OriginType: property_e.ActivityBillboardTrigger,
Type: property_e.AddSecond,
AddSecond: &receivePropertyDuration,
UpdateEndTime: nil,
}).Persistent(); err != nil {
model.Log.Error(err)
}
}
// 推送
user, err := user_m.GetUser(model, receiverUserId)
if err != nil {
return err
}
nobleDuration := days * 3600 * 24
if err := msg_m.NewUserRecord(model, user.ID, msg_e.AddNoble, user.Nick, user.ID, "", strconv.Itoa(int(nobleDuration)/(24*3600)), "", "", "").Persistent(); err != nil {
return err
}
msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
return nil
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := user_m.UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
package ride_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/property_e"
"hilo-user/domain/model/user_m"
"time"
)
type RideService struct {
svc *domain.Service
}
func NewRideService(myContext *mycontext.MyContext) *RideService {
svc := domain.CreateService(myContext)
return &RideService{svc}
}
// 下发座驾
func (s *RideService) SendRide(receiverUserId mysql.ID, rideId mysql.ID, days int) error {
model := domain.CreateModelContext(s.svc.MyContext)
// 增加座驾
receivePropertyDuration := uint32(days) * 3600 * 24
userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, rideId)
if err != nil {
return err
}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second)
if err := userProperty.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if err := (&user_m.UserPropertyLog{
Model: model,
UserId: receiverUserId,
PropertyId: rideId,
OriginType: property_e.ActivityBillboardTrigger,
Type: property_e.AddSecond,
AddSecond: &receivePropertyDuration,
UpdateEndTime: nil,
}).Persistent(); err != nil {
model.Log.Error(err)
}
return nil
}
package service
import (
"hilo-user/domain"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
"runtime/debug"
)
type Service struct {
*domain.CtxAndDb
}
func (service *Service) getMyContext() *mycontext.MyContext {
return service.MyContext
}
/**
* 创建服务
* @param
* @return
**/
func CreateService(myContext *mycontext.MyContext) *Service {
if myContext == nil {
return &Service{CtxAndDb: &domain.CtxAndDb{
Db: mysql.Db,
MyContext: mycontext.CreateMyContext(nil),
Redis: redisCli.GetRedis(),
}}
} else {
return &Service{CtxAndDb: &domain.CtxAndDb{
Db: mysql.Db,
MyContext: myContext,
Redis: redisCli.GetRedis(),
}}
}
}
//事务钩子回调,遇到错误,异常则回调,写service都需要钩子回调
func (service *Service) Transactional(callback func() error) error {
//异常回调
defer func() {
if err := recover(); err != nil {
service.Log.Errorf("doTransactional SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
service.Db.Rollback()
//为了防止给controller层造成数据错误,继续抛恐慌
panic(err)
}
}()
service.CtxAndDb.Db = mysql.Db.Begin()
err := callback()
if err != nil {
service.Db.Rollback()
return err
}
//提交
return service.Db.Commit().Error
}
package user_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"gorm.io/gorm"
"hilo-user/_const/enum/user_e"
"hilo-user/cv/headwear_cv"
"hilo-user/cv/medal_cv"
"hilo-user/cv/noble_cv"
"hilo-user/cv/property_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/country_m"
"hilo-user/domain/model/diamond_m"
"hilo-user/domain/model/groupPower_m"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/user_m"
"hilo-user/domain/model/visit_m"
"hilo-user/domain/service/cp_s"
"hilo-user/myerr"
)
type UserService struct {
svc *domain.Service
}
func NewUserService(myContext *mycontext.MyContext) *UserService {
svc := domain.CreateService(myContext)
return &UserService{svc}
}
//用户基本信息
func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang string) (*user_cv.CvUserDetail, error) {
model := domain.CreateModelContext(s.svc.MyContext)
model.Log.Infof("GetUserDetail %d begin", userId)
var user user_m.User
var err error
if err = model.DB().First(&user, userId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//统计喜欢
var likeN int64
if err := model.DB().Model(&user_m.UserLike{}).Where(&user_m.UserLike{
UserId: myUserId,
LikeUserId: userId,
}).Count(&likeN).Error; err != nil {
return nil, myerr.WrapErr(err)
}
var likeMe int64
if err := model.DB().Model(&user_m.UserLike{}).Where(&user_m.UserLike{
UserId: userId,
LikeUserId: myUserId,
}).Count(&likeMe).Error; err != nil {
return nil, myerr.WrapErr(err)
}
rel := make(map[mysql.ID]user_m.Relation, 1)
rel[userId], _ = user_m.GetRelation(model, myUserId, userId)
var wealthUserScore user_m.MatchWealthUserScore
if err := model.DB().Model(&user_m.MatchWealthUserScore{}).Where(&user_m.MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil {
if err != nil {
if err == gorm.ErrRecordNotFound {
wealthUserScore = user_m.MatchWealthUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, myerr.WrapErr(err)
}
}
}
var charmUserScore user_m.MatchCharmUserScore
if err := model.DB().Model(&user_m.MatchCharmUserScore{}).Where(&user_m.MatchCharmUserScore{
UserId: userId,
}).First(&charmUserScore).Error; err != nil {
if err != nil {
if err == gorm.ErrRecordNotFound {
charmUserScore = user_m.MatchCharmUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, myerr.WrapErr(err)
}
}
}
var activityUserScore user_m.MatchActityUserScore
if err := model.DB().Model(&user_m.MatchActityUserScore{}).Where(&user_m.MatchActityUserScore{
UserId: userId,
}).First(&activityUserScore).Error; err != nil {
if err != nil {
if err == gorm.ErrRecordNotFound {
activityUserScore = user_m.MatchActityUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, myerr.WrapErr(err)
}
}
}
isVip, expireTime, err := user_m.IsVip(userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
svip, err := rpc.GetUserSvip(model, userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
headwear, err := headwear_cv.GetCvHeadwear(userId)
if err != nil {
return nil, err
}
medals := make(map[uint64][]uint32, 0)
medals[userId], err = user_m.GetUserMedalMerge(model.Log, mysql.Db, userId)
if err != nil {
return nil, err
}
medals, medalInfo, err := medal_cv.GetMedalInfoMap(mysql.Db, medals)
if err != nil {
return nil, err
}
rooms, err := group_m.RoomLivingUserIdFilter(model, []uint64{userId})
if err != nil {
return nil, err
}
// 2022-05-13 个人详情页:当用户在加锁的房间时,不显示进入房间的图标
if g, ok := rooms[userId]; ok {
gi, err := group_m.GetGroupInfo(model, g)
if err != nil {
return nil, err
}
if gi != nil && len(gi.Password) > 0 {
rooms[userId] = ""
}
}
cp, err := cp_s.NewCpService(s.svc.MyContext).GetUserCp(userId, lang)
if err != nil {
return nil, err
} else if cp != nil && cp.CpUserInfo != nil && cp.CpUserInfo.Avatar != nil && headwear != nil {
headwear.HeadwearIcon = *cp.CpUserInfo.Avatar
}
groupPowerId, groupPowerName, err := groupPower_m.GetUserGroupPower(model, userId)
if err != nil {
return nil, err
}
powers := map[mysql.ID]uint64{userId: groupPowerId}
powerNames := map[mysql.ID]string{userId: groupPowerName}
groupPower, _ := rpc.GetGroupPower(model, groupPowerId)
up := user_m.UserProperty{}
rides, err := up.BatchGet(mysql.Db, []uint64{userId})
if err != nil {
return nil, err
}
//rp := res_m.ResProperty{}
//properties, err := rp.GetAll(mysql.Db)
_, area, err := user_m.GetUserCountryArea(model, userId)
if err != nil {
return nil, err
}
properties, err := property_cv.GetPropertyAll(mysql.Db, area)
if err != nil {
return nil, err
}
ride := property_cv.CvProperty{
Id: rides[user.ID],
PicUrl: properties[rides[user.ID]].PicUrl,
EffectUrl: properties[rides[user.ID]].EffectUrl,
SenderAvatar: properties[rides[user.ID]].SenderAvatar,
ReceiverAvatar: properties[rides[user.ID]].ReceiverAvatar,
Using: true,
}
noble, err := noble_m.FindActiveNoble(mysql.Db, userId)
if err != nil {
return nil, err
}
//判断是不是工会
userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
if err != nil {
return nil, err
}
superManagerMap, err := user_m.GetSuperManagerMap([]uint64{userId})
if err != nil {
return nil, err
}
// 群组信息
myGroups, err := group_m.FindGroupByOwner(model, userId)
if err != nil {
return nil, err
}
// 手机绑定信息
// 第三方账号绑定信息
phoneInfo := new(user_m.UserPhoneInfo)
var thirdList []int8
if userId == myUserId {
thirdList = make([]int8, 0, 5)
// 手机绑定信息
bindInfo, err := user_m.GetUserBindInfoByUserId(model, userId)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
if bindInfo != nil {
if len(bindInfo.Phone) > 2 {
phoneInfo.Phone = bindInfo.Phone[:2] + "****" + bindInfo.Phone[len(bindInfo.Phone)-2:]
}
phoneInfo.PhoneCountry = bindInfo.PhoneCountry
phoneInfo.AreaCode = bindInfo.AreaCode
phoneInfo.Icon = bindInfo.Icon
thirdList = append(thirdList, 1)
}
// 第三方账号绑定信息
thirdInfoList, err := user_m.GetUserOauthByUserId(model, userId, 0)
if err != nil {
return nil, err
}
if thirdInfoList != nil {
for _, v := range thirdInfoList {
thirdList = append(thirdList, v.ThirdPartyType)
}
}
}
// 国家管理员
countryManager, err := country_m.GetCountryMgr(model, userId)
if err != nil {
return nil, err
}
var cvCountryManager *user_cv.CVCountryManager
if countryManager != nil {
cvCountryManager = &user_cv.CVCountryManager{
Country: countryManager.Country,
Role: countryManager.Role,
}
}
return userToDetailOne(model, &user, myUserId, userTradeUnion, likeN > 0, likeMe > 0,
rel, isVip, expireTime, svip, headwear, ride, wealthUserScore.Grade, charmUserScore.Grade,
activityUserScore.Grade, medals[userId], medalInfo[userId], rooms[userId], powers[userId], powerNames[userId], groupPower,
noble, superManagerMap[userId], myGroups, phoneInfo, thirdList, cvCountryManager, cp)
}
// 单用户版,简化参数
func userToDetailOne(model *domain.Model, user *user_m.User, myUserId mysql.ID, userTradeUnion *user_m.UserTradeUnion, isLike bool, likeMe bool, hvMap map[mysql.ID]user_m.Relation,
isVip bool, vipExpireTime *int64, svip rpc.CvSvip, headwear *headwear_cv.CvHeadwear, ride property_cv.CvProperty, wealthGrade uint32, charmGrade uint32, activityGrade uint32,
medals []uint32, medalInfo []medal_cv.CvMedal, room string, power uint64, powerName string, groupPower rpc.CvGroupPowerInfo, noble *noble_m.UserNoble, isOfficialStaff bool,
myGroups []group_m.GroupInfo, phoneInfo *user_m.UserPhoneInfo, thirdList []int8, countryManager *user_cv.CVCountryManager, cp *user_cv.CvCp) (*user_cv.CvUserDetail, error) {
room, err := group_m.ToTxGroupId(model, room)
if err != nil {
model.Log.Warnf("ToTxGroupId failed for %s, err:%v", room, err)
room = ""
}
cvUserDetail := &user_cv.CvUserDetail{
CvUserBase: user_cv.CvUserBase{
Id: &user.ID,
Avatar: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
DefaultAvatar: &user.DefaultAvatar,
ExternalId: StrToString(&user.ExternalId),
Nick: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), user.Code, user.Nick)),
Description: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Description)),
Sex: TypeToUint8(&user.Sex),
Country: StrNil(user.Country),
CountryIcon: StrNil(user.CountryIcon),
Code: StrToString(&user.Code),
IsPrettyCode: user.IsPrettyCode(),
IsNew: user.IsNew(),
IsVip: isVip,
IsOfficialStaff: isOfficialStaff,
VipExpireTime: vipExpireTime,
Svip: svip,
Medals: IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals),
MedalInfo: IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo),
Headwear: IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, headwear),
Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, ride),
},
IsPush: TypeToUint8(&user.IsPush),
IsLike: &isLike,
IsLikeMe: &likeMe,
WealthUserGrade: wealthGrade,
CharmUserGrade: charmGrade,
ActivityUserGrade: activityGrade,
CurrentRoom: room,
MyGroupPower: power,
MyGroupPowerName: powerName,
GroupPower: groupPower,
PhoneInfo: phoneInfo,
ThirdList: thirdList,
CountryManager: countryManager,
Cp: cp,
}
if noble != nil {
cvUserDetail.Noble = noble_cv.CvNoble{
Level: noble.Level,
EndTime: noble.EndTime.Unix(),
}
}
//本人,计算,喜欢统计,钻石数量
if user.ID == myUserId {
cvUserDetail.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)
//喜欢统计
var userCount user_m.UserCount
err := model.DB().Where(&user_m.UserCount{
UserId: myUserId,
Type: user_e.CountTypeLikeMe,
}).First(&userCount).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(err)
}
cvUserDetail.LikeCount = NumToUint32(&userCount.Num)
//我喜欢统计
var userILikeCount user_m.UserCount
err = mysql.Db.Where(&user_m.UserCount{
UserId: myUserId,
Type: user_e.CountTypeLike,
}).First(&userILikeCount).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(err)
}
cvUserDetail.ILikeCount = NumToUint32(&userILikeCount.Num)
//访问统计
var visitCount int64
err = mysql.Db.Model(&visit_m.UserVisit{}).Where(&visit_m.UserVisit{
VisitUserId: myUserId,
}).Count(&visitCount).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(err)
}
vc := uint32(visitCount)
cvUserDetail.VisitCount = NumToUint32((*mysql.Num)(&vc))
//钻石数量
cvDiamond, err := diamond_m.GetDiamondAccountByUserId(model, myUserId)
if err != nil {
return nil, err
}
cvUserDetail.DiamondNum = &cvDiamond.DiamondNum
cvUserDetail.PinkDiamondNum = &cvDiamond.PinkDiamondNum
isAgent := user_m.IsAgent(myUserId)
cvUserDetail.IsAgentMgr = &isAgent
} else {
//不是本人
if user.IsShowAge == mysql.OPEN {
cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)
}
}
if userTradeUnion == nil {
isTradeUnionFlag := false
cvUserDetail.IsTradeUnion = &isTradeUnionFlag
cvUserDetail.IsTradeUnionMatchNotification = nil
} else {
isTradeUnionFlag := true
cvUserDetail.IsTradeUnion = &isTradeUnionFlag
isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN
cvUserDetail.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag
}
// 永恒之心的值
hv, ok := hvMap[user.ID]
if ok {
cvUserDetail.HeartValue = hv.HeartValue
cvUserDetail.HeartValueMax = hv.HeartValueMax
cvUserDetail.MeetDays = hv.MeetDays
} else {
cvUserDetail.HeartValueMax = 0
}
// 拥有的群组id
if len(myGroups) > 0 {
cvUserDetail.GroupId = myGroups[0].TxGroupId
}
return cvUserDetail, nil
}
package user_s
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 IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func IfLogoutMedals(condition bool, trueVal, falseVal []uint32) []uint32 {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutMedalInfo(condition bool, trueVal, falseVal []medal_cv.CvMedal) []medal_cv.CvMedal {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutHeadwear(condition bool, trueVal, falseVal *headwear_cv.CvHeadwear) *headwear_cv.CvHeadwear {
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 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
}
...@@ -2,32 +2,38 @@ module hilo-user ...@@ -2,32 +2,38 @@ module hilo-user
go 1.17 go 1.17
replace git.hilo.cn/hilo-common => ../hilo-common
require ( require (
git.hilo.cn/hilo-common v0.0.0-00010101000000-000000000000
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-gonic/gin v1.6.3 github.com/gin-gonic/gin v1.6.3
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.6.0
github.com/hashicorp/consul/api v1.7.0
github.com/jinzhu/copier v0.3.5 github.com/jinzhu/copier v0.3.5
github.com/joho/godotenv v1.3.0
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.7.0 github.com/sirupsen/logrus v1.7.0
github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/gin-swagger v1.2.0
github.com/swaggo/swag v1.6.7 github.com/swaggo/swag v1.6.7
golang.org/x/sync v0.0.0-20190423024810-112230192c58
gopkg.in/ini.v1 v1.63.2
gorm.io/driver/mysql v1.4.3
gorm.io/gorm v1.23.8 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 ( require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
...@@ -40,18 +46,24 @@ require ( ...@@ -40,18 +46,24 @@ require (
github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/golang/protobuf v1.3.3 // indirect github.com/go-sql-driver/mysql v1.7.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-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect github.com/hashicorp/go-hclog v0.12.0 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/serf v0.9.3 // indirect github.com/hashicorp/serf v0.9.3 // indirect
github.com/jinzhu/inflection v1.0.0 // 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/jonboulle/clockwork v0.3.0 // indirect github.com/joho/godotenv v1.3.0 // indirect
github.com/json-iterator/go v1.1.9 // 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/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 github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect
github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-colorable v0.1.6 // indirect
...@@ -60,10 +72,19 @@ require ( ...@@ -60,10 +72,19 @@ require (
github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // 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 github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.6 // 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 gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.4.3 // 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/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 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
...@@ -8,15 +11,55 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV ...@@ -8,15 +11,55 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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/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 h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 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 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/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/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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
...@@ -24,10 +67,19 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC ...@@ -24,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/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 h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 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.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= 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/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 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/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 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
...@@ -65,15 +117,44 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 ...@@ -65,15 +117,44 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 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.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.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
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 h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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/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 h1:tGs8Oep67r8CcA2Ycmb/8BLBcJ70St44mF2X10a/qPg=
github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg= github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg=
github.com/hashicorp/consul/sdk v0.6.0 h1:FfhMEkwvQl57CildXJyGHnwGGM4HMODGyfjGwNM1Vdw= github.com/hashicorp/consul/sdk v0.6.0 h1:FfhMEkwvQl57CildXJyGHnwGGM4HMODGyfjGwNM1Vdw=
...@@ -99,6 +180,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv ...@@ -99,6 +180,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
...@@ -107,6 +190,8 @@ github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC ...@@ -107,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/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 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM=
github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= 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 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
...@@ -114,6 +199,11 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr ...@@ -114,6 +199,11 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg=
...@@ -122,13 +212,16 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV ...@@ -122,13 +212,16 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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.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.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.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 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.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 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 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= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
...@@ -170,9 +263,20 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ ...@@ -170,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 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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 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 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 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 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 h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 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= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
...@@ -182,8 +286,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb ...@@ -182,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/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.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 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 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= 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/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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
...@@ -193,20 +303,33 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg ...@@ -193,20 +303,33 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 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.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= 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 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= 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.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.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 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 v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
...@@ -214,14 +337,29 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs ...@@ -214,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/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 v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 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-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-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-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-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-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-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-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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
...@@ -230,12 +368,21 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL ...@@ -230,12 +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-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-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-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 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-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-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-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
...@@ -243,44 +390,104 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h ...@@ -243,44 +390,104 @@ 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-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-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-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-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-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-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-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-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-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-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-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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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/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.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.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 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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-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-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-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-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-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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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 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-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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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/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/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 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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 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.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.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.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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k= gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= 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 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 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=
...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code ...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code
[REDIS] [REDIS]
REDIS_HOST=47.244.34.27:6379 REDIS_HOST=47.244.34.27:6379
REDIS_PASSWORD=8QZ9JD1zLvPR3yHf REDIS_PASSWORD=8QZ9JD1zLvPR3yHf
REDIS_CLUSTER_HOST=47.244.34.27:6379
REDIS_CLUSTER_PASSWORD=8QZ9JD1zLvPR3yHf
[JWT] [JWT]
SECRET=hilo1632 SECRET=hilo1632
ISSUER_API=hiloApi ISSUER_API=hiloApi
...@@ -59,12 +61,12 @@ TX_OVERSEA_APP_ID=40000066 ...@@ -59,12 +61,12 @@ TX_OVERSEA_APP_ID=40000066
TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c
[EMAS] [EMAS]
REGION_ID=cn-hangzhou REGION_ID=cn-hangzhou
ACCESS_KEY_ID=LTAI4FhNPzxdzD4w6bHirL9Z ACCESS_KEY_ID=LTAIdQZv5H1kNZp5
ACCESS_KEY_SECRET=OQvUJpXDrjGi3g1F2aHiAIFWIvLdbP ACCESS_KEY_SECRET=UnwY0ClDkqBMLwPx3OJJiLYyk9xYLO
ANDROID_APP_KEY=30250713 ANDROID_APP_KEY=30250713
ANDROID_APP_SECRET=cae7b9a9d3e54577d2c3b60bf6d23047 ANDROID_APP_SECRET=cae7b9a9d3e54577d2c3b60bf6d23047
IOS_APP_KEY=30240346 IOS_APP_KEY=30790728
IOS_APP_SECRET=57f33ab9ca6a957a8c659f2b0b6d1205 IOS_APP_SECRET=4fd69ca084c67d4b5a8d15452f0af26a
APNS=DEV APNS=DEV
[AGORA] [AGORA]
APP_ID=fc3e087f701b4f788099e1924c3cc7b0 APP_ID=fc3e087f701b4f788099e1924c3cc7b0
......
...@@ -2,18 +2,24 @@ package main ...@@ -2,18 +2,24 @@ package main
import ( import (
"fmt" "fmt"
"hilo-user/resource/consul" "git.hilo.cn/hilo-common/resource/consul"
"git.hilo.cn/hilo-common/resource/redisCli"
"hilo-user/cron"
"hilo-user/domain/service/event_s"
"hilo-user/route" "hilo-user/route"
) )
const ( const (
PORT = 9040 PORT = 9040
RegisterName = "hiloUser"
RegisterTag = "用户中心"
) )
func main() { func main() {
//cron.Init() // 开启定时任务 cron.Init() // 开启定时任务
//event_s.EventInit() // 注册事件(内部事件+mysql拟kafka) event_s.EventInit() // 注册事件(内部事件+mysql拟kafka)
redisCli.InitCluster() // redis集群
r := route.InitRouter() // 注册路由 r := route.InitRouter() // 注册路由
consul.RegisterToConsul(PORT) // 服务注册 consul.RegisterToConsul(PORT, RegisterName, RegisterTag) // 服务注册
r.Run(fmt.Sprintf(":%d", PORT)) // 启动服务 r.Run(fmt.Sprintf(":%d", PORT)) // 启动服务
} }
package mycontext
import (
"context"
uuid "github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
"hilo-user/_const"
"hilo-user/mylogrus"
"strconv"
"strings"
)
/**
* 主要是完成日志打印
* @param
* @return
**/
type MyContext struct {
context.Context
Log *logrus.Entry
Cxt map[string]interface{}
}
func CreateMyContextWith(traceId interface{}) *MyContext {
cxt := map[string]interface{}{}
cxt[_const.TRACEID] = traceId
return CreateMyContext(cxt)
}
func CreateMyContext(ctx map[string]interface{}) *MyContext {
var traceId string
if traceIdTemp, ok := ctx[_const.TRACEID]; ok {
traceId, ok = traceIdTemp.(string)
} else {
traceId = strings.Replace(uuid.NewV4().String(), "-", "", -1)
}
var userId string
if userIdTemp, ok := ctx[_const.USERID]; ok {
userId = strconv.FormatUint(userIdTemp.(uint64), 10)
}
var deviceTypeStr string
if deviceTypeTemp, ok := ctx[_const.DEVICETYPE]; ok {
deviceTypeStr, ok = deviceTypeTemp.(string)
}
var sAppVersion string
if appVersionTmp, ok := ctx[_const.APP_VERSION]; ok {
sAppVersion, ok = appVersionTmp.(string)
}
var url string
if urlTmp, ok := ctx[_const.URL]; ok {
url, ok = urlTmp.(string)
}
var method string
if methodTmp, ok := ctx[_const.METHOD]; ok {
method, ok = methodTmp.(string)
}
_ctx := context.WithValue(context.Background(), "traceId", traceId)
_ctx = context.WithValue(_ctx, "userId", userId)
return &MyContext{
Context: _ctx,
Log: CreateContextLog(userId, traceId, deviceTypeStr, sAppVersion, url, method),
Cxt: ctx,
}
}
/**
* 创建上下文的日志
**/
func CreateContextLog(userId string, traceId string, deviceType string, deviceVersion string, url string, method string) *logrus.Entry {
return mylogrus.MyLog.WithFields(logrus.Fields{
_const.USERID: userId,
_const.TRACEID: traceId,
_const.DEVICETYPE: deviceType,
_const.APP_VERSION: deviceVersion,
_const.URL: url,
_const.METHOD: method,
})
}
...@@ -6,11 +6,14 @@ import ( ...@@ -6,11 +6,14 @@ import (
var ( var (
// 一般性错误 // 一般性错误
HttpSecret = myerr.NewBusinessCode(1000, "http secret err", myerr.BusinessData{})
TokenInvalid = myerr.NewBusinessCode(1001, "token invalid", myerr.BusinessData{}) TokenInvalid = myerr.NewBusinessCode(1001, "token invalid", myerr.BusinessData{})
ExternalIdNoExist = myerr.NewBusinessCode(1003, "externalId no exist", myerr.BusinessData{}) ExternalIdNoExist = myerr.NewBusinessCode(1003, "externalId no exist", myerr.BusinessData{})
CodeNoExist = myerr.NewBusinessCode(1005, "code no exist", myerr.BusinessData{}) CodeNoExist = myerr.NewBusinessCode(1005, "code no exist", myerr.BusinessData{})
ParaMissing = myerr.NewBusinessCode(1006, "parameter missing", myerr.BusinessData{}) ParaMissing = myerr.NewBusinessCode(1006, "parameter missing", myerr.BusinessData{})
InvalidParameter = myerr.NewBusinessCode(1009, "Invalid parameter", myerr.BusinessData{}) InvalidParameter = myerr.NewBusinessCode(1009, "Invalid parameter", myerr.BusinessData{})
IncorrectState = myerr.NewBusinessCode(1013, "Incorrect state", myerr.BusinessData{})
TransactionFailed = myerr.NewBusinessCode(1014, "Transaction failed", myerr.BusinessData{})
ReqTooFrequent = myerr.NewBusinessCode(1018, "Requests are too frequent", myerr.BusinessData{}) ReqTooFrequent = myerr.NewBusinessCode(1018, "Requests are too frequent", myerr.BusinessData{})
// 钻石 // 钻石
...@@ -18,30 +21,17 @@ var ( ...@@ -18,30 +21,17 @@ var (
DiamondFrequency = myerr.NewBusinessCode(4001, "Diamond operation frequency too high", myerr.BusinessData{}) DiamondFrequency = myerr.NewBusinessCode(4001, "Diamond operation frequency too high", myerr.BusinessData{})
DiamondAccountFrozen = myerr.NewBusinessCode(4004, "Diamond Account Frozen", myerr.BusinessData{}) DiamondAccountFrozen = myerr.NewBusinessCode(4004, "Diamond Account Frozen", myerr.BusinessData{})
// 游戏 ResPropertyDiamondNoUse = myerr.NewBusinessCode(5004, "Property can not buy", myerr.BusinessData{}) //头饰不能买
GameInvalidParameter = myerr.NewGameError(10002, "invalid parameter")
GameTokenInvalid = myerr.NewGameError(1004, "user token invalid")
GameTokenExpire = myerr.NewGameError(1005, "user token expire")
CpNotRelation = myerr.NewBusinessCode(6000, "cp not relation", myerr.BusinessData{})
// 群组 // 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群 GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
// 游戏服务的错误码,6位,50XXX CpAlreadyInvite = myerr.NewBusinessCode(50120, "Already invited", myerr.BusinessData{}) // 已经发送过邀请了
GameAddNoPermissions = myerr.NewBusinessCode(50100, "Only room administrators can create users", myerr.BusinessData{}) // 权限不足 CpHaveCancelNoDeal = myerr.NewBusinessCode(50121, "You have a cancel apply", myerr.BusinessData{}) // 有接触申请需要处理
GameAddNotOnMic = myerr.NewBusinessCode(50101, "Need on mic", myerr.BusinessData{}) // 需要在麦上才能创建、加入游戏 InviteApplyNoPermission = myerr.NewBusinessCode(50122, "This user does not have invitation permission", myerr.BusinessData{}) // 该用户没有邀请权限
GameHaveNoEnd = myerr.NewBusinessCode(50102, "Group user have no end", myerr.BusinessData{}) // 房间还有未结束的游戏 InviteApplyAlreadyInvited = myerr.NewBusinessCode(50123, "Already invited by someone else", myerr.BusinessData{}) // 已经被别人邀请了
GameNotFound = myerr.NewBusinessCode(50103, "Game not found", myerr.BusinessData{}) // InviteApplyCodeInvalid = myerr.NewBusinessCode(50124, "user id invalid", myerr.BusinessData{}) // 邀请人用户id错误
GameStart = myerr.NewBusinessCode(50104, "Gaming", myerr.BusinessData{}) // InviteApplyNewCodeInvalid = myerr.NewBusinessCode(50125, "user id invalid", myerr.BusinessData{}) // 被邀请人用户id错误
GameAlreadyJoin = myerr.NewBusinessCode(50105, "Already Joined", myerr.BusinessData{}) // 已经加入了游戏 InviteApplyTimes = myerr.NewBusinessCode(50126, "Your application today has reached the upper limit, please wait for tomorrow to continue the application", 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{}) // 加入失败
) )
...@@ -2,8 +2,9 @@ package myerr ...@@ -2,8 +2,9 @@ package myerr
import ( import (
"fmt" "fmt"
"git.hilo.cn/hilo-common/myerr"
"git.hilo.cn/hilo-common/mylogrus"
"github.com/pkg/errors" "github.com/pkg/errors"
"hilo-user/mylogrus"
"strconv" "strconv"
) )
...@@ -226,35 +227,10 @@ func WrapErr(err error) error { ...@@ -226,35 +227,10 @@ func WrapErr(err error) error {
} }
} }
func WrapGameErr(err error) error { func ToLocal(err *myerr.BusinessError) error {
if err == nil { return &BusinessError{
return err code: err.GetCode(),
} message: err.GetMsg(),
if h, ok := err.(*GameError); ok { err: err.GetErr(),
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 + "}"),
} }
} }
package mylogrus
import (
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"io"
"os"
"path/filepath"
"time"
)
const logDir = "/var/log/hilo/"
var filenamePrefix string
var MyLog = logrus.New()
func Info(v interface{}) {
MyLog.Info("")
}
func init() {
filenamePrefix = logDir + filepath.Base(os.Args[0]) + "."
// stderr日志重定向
MyLog.SetOutput(os.Stdout)
RewriteStderrFile()
MyLog.SetFormatter(&logrus.TextFormatter{
ForceQuote: false,
DisableQuote: true,
TimestampFormat: "2006-01-02 15:04:05.000",
FullTimestamp: true,
})
hook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: getLevelWrite(logrus.DebugLevel),
logrus.InfoLevel: getLevelWrite(logrus.InfoLevel),
logrus.WarnLevel: getLevelWrite(logrus.WarnLevel),
logrus.ErrorLevel: getLevelWrite(logrus.ErrorLevel),
logrus.FatalLevel: getLevelWrite(logrus.FatalLevel),
logrus.PanicLevel: getLevelWrite(logrus.PanicLevel),
}, &logrus.TextFormatter{ForceQuote: false, DisableQuote: true, TimestampFormat: time.RFC3339Nano})
MyLog.AddHook(hook)
MyLog.SetLevel(logrus.InfoLevel)
MyLog.SetReportCaller(true)
}
func GetInfoLog() io.Writer {
return getLevelWrite(logrus.InfoLevel)
}
func getLevelWrite(level logrus.Level) io.Writer {
var name string
switch level {
case logrus.DebugLevel:
name = "debug.log"
case logrus.InfoLevel:
name = "info.log"
case logrus.WarnLevel:
name = "warn.log"
case logrus.ErrorLevel:
name = "error.log"
case logrus.FatalLevel:
name = "fatal.log"
case logrus.PanicLevel:
name = "panic.log"
}
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
func GetSqlLog() io.Writer {
var name string = "sql.log"
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
//go:build !windows
// +build !windows
package mylogrus
import (
"fmt"
"os"
"path/filepath"
"runtime"
"syscall"
"time"
)
var stdErrFileHandler *os.File
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
//if runtime.GOOS == "darwin" { // mac本地调试
// filename = "./log/hilo/" + filepath.Base(os.Args[0]) + ".stderr.log"
//}
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Println(err)
return
}
stdErrFileHandler = file //把文件句柄保存到全局变量,避免被GC回收
if err = syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
fmt.Println(err)
return
}
// 内存回收前关闭文件描述符
runtime.SetFinalizer(stdErrFileHandler, func(fd *os.File) {
fd.Close()
})
return
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
//go:build windows
// +build windows
package mylogrus
import (
"os"
"path/filepath"
"time"
)
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
MyLog.Errorf("stderr log in:%v,err:%v", file, err)
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
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', "منسوخ کر دیا گیا ہے۔");
CREATE TABLE `invite_apply` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '发起申请者',
`new_user_id` bigint NOT NULL COMMENT '被邀请的人',
`platform` varchar(20) NOT NULL COMMENT '来自平台',
`platform_id` varchar(150) NOT NULL COMMENT '平台id',
`recharge_info` varchar(50) NOT NULL COMMENT '新用户在其它平台充值的标志',
`status` tinyint unsigned NOT NULL COMMENT '状态0.未审核1.已通过2.已拒绝',
`level` varchar(5) NOT NULL DEFAULT '' COMMENT '申请等级(S,A,B,C)',
`video_url` varchar(400) NOT NULL COMMENT '上传的视频url',
`reason` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '拒绝原因',
`sub_user_id` bigint NOT NULL COMMENT '提交人',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`) USING BTREE,
KEY `new_user_id` (`new_user_id`) USING BTREE,
KEY `platform` (`platform`) USING BTREE,
KEY `platform_id` (`platform_id`) USING BTREE,
KEY `status` (`status`) USING BTREE,
KEY `created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='新人邀请申请';
INSERT INTO hilo.res_msg_translate (`language`, title, content, icon_url, msg_type, `type`, action_type, action_url)
VALUES ('en', '', 'The welcome party application of user {nick} (ID: {diamondIncome}) has been approved, the welcome party level is: {dayNum} level, inviter {beanNum} (ID: {groupCode})', '', 1, 59, 0, ''),
('tr', '', '{nick} kullanıcısının (ID: {diamondIncome}) karşılama partisi uygulaması onaylandı, karşılama partisi seviyesi: {dayNum} seviyesi, davet eden {beanNum} (ID: {groupCode})', '', 1, 59, 0, ''),
('en', '', 'The welcome party application of user {nick} (ID: {diamondIncome}) has been rejected. The reason for the rejection is: {dayNum}, inviter {beanNum} (ID: {groupCode})', '', 1, 60, 0, ''),
('tr', '', '{nick} kullanıcısının (ID: {diamondIncome}) karşılama partisi başvurusu reddedildi. Reddedilme nedeni: {dayNum}, davet eden {beanNum} (ID: {groupCode})', '', 1, 60, 0, ''),
('en', '', 'Welcome party application, please click to enter', 'https://image.whoisamy.shop/hilo/manager/welcomeparty.png', 1, 61, 1, 'https://h5.whoisamy.shop/action/hiloHtml/2023Activity/2023_7_03WelcomeParty/index.html'),
('tr', '', 'hoşgeldin partisi uygulaması, girmek için lütfen tıklayınız', 'https://image.whoisamy.shop/hilo/manager/welcomeparty.png', 1, 61, 1, 'https://h5.whoisamy.shop/action/hiloHtml/2023Activity/2023_7_03WelcomeParty/index.html');
INSERT INTO mgr_permission_config (id, parent_id, name, method_url, `type`)
VALUES(3224, 2663, '欢迎派对审核', 'POST:/v1/mgr/invite/apply?$', 0),
(3225, 2663, '欢迎派对审核-列表', 'GET:/v1/mgr/invite/apply?$', 0);
syntax = "proto3";
package biz;
option go_package = "protocol/biz";
/* id = 1 */
message BizMessage {
uint32 type = 2;
string payLoad = 3;
}
/* id = 2 */
message BizMessageRsp {
uint32 status = 1;
}
service Transmitter {
rpc process(BizMessage) returns (BizMessageRsp) {}
}
\ No newline at end of file
syntax = "proto3";
package userCenter;
option go_package = "protocol/userCenter";
/* id = 1 */
message RouteMessage {
uint64 uid = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 2 */
message RouteMessageRsp {
uint32 status = 1;
}
/* id = 3 */
message LoginMessage {
string proxyAddr = 1; // userProxy的地址:ip:port
string token = 2;
string clientAddr = 3; // 客户端地址(websocket):ip:port
}
/* id = 4 */
message LoginMessageRsp {
uint32 status = 1;
uint64 uid = 2;
}
/* id = 5 */
message LogoutMessage {
string clientAddr = 1; // 客户端地址(websocket):ip:port
uint64 uid = 2;
}
/* id = 6 */
message LogoutMessageRsp {
uint32 status = 1;
}
/* id = 7 */
message MulticastMessage {
repeated uint64 uids = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 8 */
message MulticastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 9 */
message KickMessage {
uint64 uid = 1;
string addr = 2;
}
/* id = 10 */
message KickMessageRsp {
uint32 status = 1;
}
/* id = 11 */
message BroadcastMessage {
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 12 */
message BroadcastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 13 */
message BizMessage {
uint64 uid = 1;
uint32 msgType = 2;
string payLoad = 3;
}
/* id = 14 */
message BizMessageRsp {
uint32 status = 1;
}
service Router {
rpc route(RouteMessage) returns (RouteMessageRsp) {}
rpc kickUser(KickMessage) returns (KickMessageRsp) {}
}
service User {
rpc login(LoginMessage) returns (LoginMessageRsp) {}
rpc logout(LogoutMessage) returns (LogoutMessageRsp) {}
rpc multicast(MulticastMessage) returns (MulticastMessageRsp) {}
rpc broadcast(BroadcastMessage) returns (BroadcastMessageRsp) {}
rpc transmit(BizMessage) returns (BizMessageRsp) {}
}
\ No newline at end of file
syntax = "proto3";
package userProxy;
option go_package = "protocol/userProxy";
/* id = 1 登录*/
message Login {
string token = 1;
}
/* id = 2 登录的回应 */
message LoginRsp {
uint32 status = 1;
}
/* id = 3 客户端心跳 */
message HeartBeat {
string externalUid = 1;
}
/* id = 4 客户端心跳的回应 */
message HeartBeatRsp {
uint32 status = 1;
}
/* id = 7 客户端上行消息 */
message BizRequest {
uint32 type = 1;
string payLoad = 2;
}
/* id = 8 客户端上行消息的应答 */
message BizResponse {
uint32 status = 1;
}
/* id == 100 匹配结果通知 waitDuration:开始/下一个时间 matchUniqueId:匹配一对的唯一标识码, status:是否是落单 singleWaitTimeInSec:单方等待连接最长时间 dualWaitTimeInSec:双方连接中最长时间*/
message MatchSuccess {
string localUserId = 1;
string remoteUserId = 2;
uint32 waitDuration = 3;
string matchUniqueId = 4;
bool status = 5;
uint32 singleWaitTimeInSec = 6;
uint32 dualWaitTimeInSec = 7;
}
/* id == 101 匹配后用户选择结果通知, failType: 只有status=2 才有值,其它为0,failType=1:等待时间到了,拒绝 failType=2:主动拒绝 */
message MatchConfirm {
uint32 status = 1;
string channelId = 2;
string token = 3;
string localUserId = 4;
string remoteUserId = 5;
uint32 remoteAgoraId = 6;
uint32 callDuration = 7;
uint32 localAgoraId = 8;
uint32 diamondBalance = 9;
string matchUniqueId = 10;
uint32 failType = 11;
}
/* id == 102 视频通话准备 */
message CallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 103 礼物加时 */
message AddTimeGift {
uint32 giftId = 1;
string token = 2;
uint32 duration = 3;
uint64 endTimestamp = 4;
string channelId = 5;
bool isSender = 6;
uint32 giftNum = 7;
string iconUrl = 8;
string svgaUrl = 9;
string senderAvatar = 10;
string receiverAvatar = 11;
}
/* id == 104 免费加时 */
message AddTimeFree {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
}
/* id == 105 退出 */
message ConnectsQuit {
uint64 from_user_id = 1;
}
/* id == 106 连接状态 */
message ConnectStatus {
uint64 from_user_id = 1;
float user_diamonds = 2;
bool diamonds_enough = 3;
}
/* id == 107 ??? */
message ConnectsCall {
uint64 from_user_id = 1;
string rong_room_name = 2;
bool is_join = 3;
}
/* id == 108 */
message ConnectCommon {
string rong_room_name = 1;
uint64 from_user_id = 2;
string extra = 3;
string message = 4;
}
/* id == 109 召回授权弹框 */
message RecallWindow {
}
/* id == 110 视频发送 status:(1:接收到邀请, 2:接收到对方同意, 3:双方拒绝(还没接通), 4:对方挂断(接通后)diamondBalance 只有status=2,才出现)*/
message Video {
string videoUniqueId = 1;
string channelId = 2;
uint32 localAgoraId = 3;
uint32 remoteAgoraId = 4;
string agoraToken = 5;
string sendUserId = 6;
string receiveUserId = 7;
uint32 status = 8;
uint32 diamondBalance = 9;
}
/* id == 111 视频通话准备 */
message VideoCallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 112 互相喜欢 */
message LikeEach {
string remoteUserId = 1;
}
/* id == 113 喜欢我 */
message LikeMe {
string remoteUserId = 1;
string remoteNick = 2;
string channelId = 3;
}
/* id == 114 日常进入app,获取钻石 */
message DailyInAppDiamond {
uint32 diamondNum = 1;
}
/* id == 115 横幅 */
message GlobalGiftBanner {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
string sendUserCode = 7;
string sendUserAvatar = 8;
string sendUserNick = 9;
string receiveUserNick = 10;
string giftPicUrl = 11;
}
/* id == 116 横幅的回应,用来测量RTT */
message GlobalGiftBannerRsp {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
}
/*id==117 幸运转盘通知,客户端重新拉取查询, type:客户端不用理*/
message LuckyWheel {
string groupId = 1;
uint32 type = 2;
}
/* id == 118 幸运转盘获胜者全服广播 */
message LuckyWheelBanner {
uint32 diamondNum = 1;
string sendUserId = 2;
string groupId = 3;
string nick = 4;
string code = 5;
string avatar = 6;
}
/* id == 119 幸运转盘钻石变化 */
message LuckyWheelDiamondChange {
string groupId = 1;
}
/* id == 120 服务器配置变更 */
message ConfigChange {
uint32 type = 1;
}
/* id == 121 全局火箭横幅 */
message GlobalRocketNotice {
string groupId = 1;
string period = 2;
uint32 round = 3;
uint32 stage = 4;
string topUserIcon = 5;
string nick = 6;
string code = 7;
string avatar = 8;
}
/* id == 122 群发功能弹窗 */
message GroupSendNotice {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string text = 5;
string groupName = 6;
string groupCode = 7;
string groupAvatar = 8;
uint32 userInNum = 9; // 最近进入房间的人数
string groupId = 10;
}
/* id == 123 全球消息 */
message GlobalBroadcast {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string senderNick = 5;
string msg = 6;
string groupId = 7;
uint32 senderNobleLevel = 8;
}
/* id == 124 全球消息 */
message MicTaskFinish {
string userId = 1;
uint32 diamond = 2;
}
/* id == 125 水果机开奖通知 */
message FruitMachine {
string date = 1;
uint32 round = 2;
}
/* id == 126 贵族变化 */
message NobleChange {
}
/* id == 127 加入群组成功 */
message JoinGroup {
string groupId = 1;
string externalId = 2;
}
/* id == 128 1对1视频1分钟加时成功 */
message VideoTimeMinuteSuccess {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
string videoUniqueId = 6;
bool isSend = 7;
uint32 sendRemainDiamond = 8;
}
/* id == 129 1对1视频1分钟加时询问检查 */
message VideoTimeMinuteCheck {
string videoUniqueId = 1;
uint32 diamond = 2;
string uuid = 3;
}
/* id == 130 1对1视频,错过 */
message VideoMiss {
uint32 totalNum = 1;
}
/* id == 131 进房,群组活动信息 */
message GroupActivity {
string ActivityId = 1;// id
uint64 StartAt = 2; // 开始时间戳,东八区时间戳
uint64 EndAt = 3; // 结束时间戳,东八区时间戳
string Banner = 4; // banner url
int32 AcType = 5; // 类型1.游戏2.比赛3.排队4.诗歌
string Theme = 6; // 活动主题
int32 PersonNum = 7; // 订阅人数
bool IsSubscribe = 8; // 我是否订阅该活动
string GroupId = 9; // 群id
}
\ No newline at end of file
syntax = "proto3";
package video;
option go_package = "protocol/video";
/* id = 1 视频加时 */
message VideoMinuteConfirm {
string videoUid = 1;
string externalId = 2;
}
/* id = 2 视频加时的应答 */
message VideoMinuteConfirmRsp {
uint32 status = 1;
}
[DATABASE] [DATABASE]
MYSQL_HOST=ua4papc3hmgqf351pbej-rw4rm.rwlb.dubai.rds.aliyuncs.com MYSQL_HOST=ua4papc3hmgqf351pbej-rw4rm.rwlb.dubai.rds.aliyuncs.com
MYSQL_USERNAME=nextvideo MYSQL_USERNAME=hilo_user
MYSQL_PASSWORD=ihlUwI4nhi9W88MI MYSQL_PASSWORD=ihlUwI4nhi9W88MI
MYSQL_DB=hilo MYSQL_DB=hilo
[DATABASECODE] [DATABASECODE]
...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code ...@@ -11,6 +11,8 @@ MYSQL_DB=hilo_code
[REDIS] [REDIS]
REDIS_HOST=r-eb3btxn8vfdsuwdbuf.redis.dubai.rds.aliyuncs.com:6379 REDIS_HOST=r-eb3btxn8vfdsuwdbuf.redis.dubai.rds.aliyuncs.com:6379
REDIS_PASSWORD= REDIS_PASSWORD=
REDIS_CLUSTER_HOST=r-eb3yt6k8zgxs62kjjs.redis.dubai.rds.aliyuncs.com:6379
REDIS_CLUSTER_PASSWORD=
[JWT] [JWT]
SECRET=hilo1504 SECRET=hilo1504
ISSUER_API=hiloApi ISSUER_API=hiloApi
......
package jwt package jwt
import ( import (
"git.hilo.cn/hilo-common/resource/config"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/resource/config"
"time" "time"
) )
......
package req package req
import ( 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" "github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/cache/user_c" "hilo-user/domain/cache/user_c"
"hilo-user/domain/model/res_m" "hilo-user/domain/model/res_m"
"hilo-user/mycontext"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
) )
// 分页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) { func GetUserId(c *gin.Context) (mysql.ID, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok { if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64) userId := userIdStr.(uint64)
return userId, nil return userId, nil
} }
return 0, bizerr.ParaMissing 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 // 获取userId和externalId
func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) { func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok { if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64) userId := userIdStr.(uint64)
externalId, ok := c.Get(_const.EXTERNAL_ID) externalId, ok := c.Get(mycontext.EXTERNAL_ID)
if ok { if ok {
return userId, externalId.(string), nil return userId, externalId.(string), nil
} else { } else {
...@@ -40,11 +65,11 @@ func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID ...@@ -40,11 +65,11 @@ func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID
// 获取userId和ExtId和code // 获取userId和ExtId和code
func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, string, error) { func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok { if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64) userId := userIdStr.(uint64)
userCode, ok1 := c.Get(_const.CODE) userCode, ok1 := c.Get(mycontext.CODE)
externalId, ok2 := c.Get(_const.EXTERNAL_ID) externalId, ok2 := c.Get(mycontext.EXTERNAL_ID)
if ok1 && ok2 { if ok1 && ok2 {
return userId, externalId.(string), userCode.(string), nil return userId, externalId.(string), userCode.(string), nil
} else { } else {
...@@ -60,10 +85,10 @@ func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.I ...@@ -60,10 +85,10 @@ func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.I
// 获取userId和LANGUAGE // 获取userId和LANGUAGE
func GetUserIdLang(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) { func GetUserIdLang(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok { if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64) userId := userIdStr.(uint64)
lang, ok := c.Get(_const.LANGUAGE) lang, ok := c.Get(mycontext.LANGUAGE)
if ok { if ok {
return userId, lang.(string), nil return userId, lang.(string), nil
} else { } else {
......
package config
import (
"github.com/joho/godotenv"
"gopkg.in/ini.v1"
"hilo-user/mylogrus"
"os"
"runtime"
"strconv"
)
// 数据库的配置
type MysqlConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
type MysqlCodeConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
// redis配置
type RedisConfig struct {
REDIS_HOST string
REDIS_PASSWORD string
}
// jwt
type JwtConfig struct {
SECRET string
ISSUER_API string
ISSUER_MGR string
EXPIRE string
}
// jwt
type GameJwtConfig struct {
SECRET string
ISSUER_CLIENT string
ISSUER_SERVER string
EXPIRE string
}
// oss
type OssConfig struct {
OSS_ACCESS_KEY_ID string
OSS_ACCESS_KEY_SECRET string
OSS_ROLE_ARN string
OSS_END_POINT string
OSS_BUCKET string
OSS_CDN string
OSS_EXPIRED_TIME uint
OSS_STS_POINT string
OSS_STS string
OSS_STS_AES string
}
// aws
type AwsConfig struct {
AWS_BUCKET string
AWS_CDN string
AWS_DIR string
CONFIDENCE float32
}
// APP
type AppConfig struct {
BIZ_SECRET string
WEB_SECRET string
OPERATION_SECRET string
SUPERUSER string
OFFICIAL_GROUP string
MINIMAL_VERSION_ANDROID int
MINIMAL_VERSION_IOS int
MODERATE string
}
// googlePay 配置信息
type GooglePayConfig struct {
JsonKey []byte
}
// 融云
type RongyunConfig struct {
RONG_CLOUD_APP_KEY string
RONG_CLOUD_APP_SECRET string
RONG_CLOUD_URL string
}
// 腾讯云
type TencentyunConfig struct {
TENCENTYUN_APP_ID int
TENCENTYUN_KEY string
TX_OVERSEA_APP_ID int
TX_OVERSEA_KEY string
}
// emas
type EmasConfig struct {
ANDROID_APP_KEY string
ANDROID_APP_SECRET string
REGION_ID string
ACCESS_KEY_ID string
ACCESS_KEY_SECRET string
IOS_APP_KEY string
IOS_APP_SECRET string
APNS string
}
// 声网
type AgoraConfig struct {
APP_ID string
APP_CERTIFICATE string
CUSTOMER_KEY string
CUSTOMER_SECRET string
}
// 匹配的配置
type MatchConfig struct {
//一开始匹配的默认时长(单位:秒)
MATCH_FREE_TIME int
//一开始匹配的默认时长(单位:秒)VIP
MATCH_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
MATCH_ADD_TIME_FREE int
//匹配的声网的延迟加时(单位:秒)
MATCH_AGORA_TIME int
//匹配周期(单位:秒)
MATCH_CYCLE int
//过期时间(单位:秒),用户redisCache时间
MATCH_USER_EXPIRES int
//pb match_success中, wait_duration 开始/下一个时间(单位:秒)
MATCH_SUCCESS_WAIT_DURATION uint32
//pb match_success中, single_wait_time_in_sec 单方等待连接最长时间(单位:秒)
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC uint32
//pb match_success中, dual_wait_time_in_sec 双方连接中最长时间(单位:秒)
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC uint32
}
// 在线
type OnlineConfig struct {
//在线周期
ONLINE_CYCLE int
//在线过期时间
ONLINE_USER_EXPIRES int
}
// 1对1视频
type VideoConfig struct {
VIDEO_DAILY_FREE_NUM int
//一开始匹配的默认时长(单位:秒)
VIDEO_FREE_TIME int
//一开始匹配的默认时长(单位:秒),vip
VIDEO_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
VIDEO_ADD_TIME_FREE int
//声网的延迟加时(单位:秒)
VIDEO_AGORA_TIME int
//1分钟视频,普通用户价格
VIDEO_MINUTE_NORMAL int
//1分钟视频,公会用户价格
VIDEO_MINUTE_UNION int
}
// 会话
type SessionConfig struct {
SESSION_DAILY_FREE_NUM int
GUILD_USER_HELLO_DAY int
}
type BeanConfig struct {
DIAMOND_BEAN_RATE int
}
type H5Config struct {
USER_LEVEL string
GROUP_SUPPORT string
LUCKY_WHEEL string
WEEKLY_STAR string
WEEKLY_CP string
COUNTRY_STAR string
NOBLE_BUY_IOS string
GUILD_DATA_URL string
MGR_GUILD_DATA_URL string
RANKING_PINK_DIAMOND_URL string
}
type GroupImConfig struct {
MSG_SORT_EXPIRE int
MSG_SORT_SNAP int
MSG_PARALLEL_SIZE int
}
type GradeConfig struct {
//魅力速度
CHARM_SPEED_VIP int
//活跃
ACTITY_SPEED_VIP int
//财富
WEALTH_SPEED_VIP int
}
type LikeConfig struct {
//喜欢人数
I_LIKE_NUM int
//喜欢人数VIP
I_LIKE_NUM_VIP int
//喜欢人数贵族
I_LIKE_NUM_NOBLE int
}
type ApplePayConfig struct {
PASSWORD string
}
type RegisterConfig struct {
IMEI_TOTAL int
IMEI_OAUTH int
ACCOUNT_IP int
ACCOUNT_IP_DURATION int
}
type BannerConfig struct {
GIFT_BANNER_LEVEL1 int
GIFT_BANNER_LEVEL2 int
GIFT_BANNER_LEVEL3 int
}
type DiamondConfig struct {
DAILY_LOGIN_IMEI_LIMIT int
DAILY_LOGIN_IP_LIMIT int
PRIVATE_GIFT_RETURN int
NEW_USER_INVITE_AWARD uint32
}
type LuckWheelConfig struct {
MINIMAL_PARTICIPANT int // 轮盘开始最少需要的参与人数
WAIT_TIMELONG int // 等待轮盘开始的时长(分钟)
WINNER_DIAMOND_BANNER int //全服广播钻石门槛
}
// 自定义主题
type GroupCustomThemeConfig struct {
PIC_LIMIT int //图片数量
DAY int //有效天数
}
type GiftConfig struct {
WALL_DIAMOND int //上礼物墙,礼物钻石金额
}
type DailyConfig struct {
LOGIN_COMMON int
LOGIN_VIP int
}
type FruitTycoonConfig struct {
BIG_WINNER_THRESDHOLD uint
BIG_WINNER_LOW uint
BIG_WINNER_HIGH uint
POOL_RATIO uint32
WATERMELON_RATIO uint32
}
type ActivityConfig struct {
COUNTRY_STAR_POOL_RATIO uint32
COUNTRY_STAR_ORDINARY_RATIO uint32
}
type CheckoutConfig struct {
URL string
AUTHORIZATION string
H5 string
HILO_SECRET_KEY string
}
type RiskControlConfig struct {
USER_QPS_LIMIT int64
USER_URL_QPS_LIMIT int64
}
type PayerMaxConfig struct {
URL string
KEY string
MERCHANT_ID string
BIZ_TYPE string
VERSION string
FRONT_CALLBACK_URL string
SHOW_RESULT string
EXPIRE_TIME string
LANGUAGE string
}
type SudConfig struct {
API_LIST string
}
type URLConfig struct {
BIZ_HTTP string
}
const (
LOCAL string = "local"
DEBUG string = "debug"
RELEASE string = "release"
)
var mysqlConfigData MysqlConfig
var mysqlCodeConfigData MysqlCodeConfig
var redisConfigData RedisConfig
var jwtConfigData JwtConfig
var userJwtConfigData GameJwtConfig
var appConfigData AppConfig
var ossConfigData OssConfig
var awsConfigData AwsConfig
var googlePayData GooglePayConfig
var rongyunData RongyunConfig
var tencentyunData TencentyunConfig
var emasData EmasConfig
var agora AgoraConfig
var matchData MatchConfig
var onlineData OnlineConfig
var sessionData SessionConfig
var videoData VideoConfig
var beanData BeanConfig
var h5Data H5Config
var groupImData GroupImConfig
var gradeData GradeConfig
var likeData LikeConfig
var applePayData ApplePayConfig
var registerData RegisterConfig
var bannerConfig BannerConfig
var diamondConfig DiamondConfig
var luckyWheelConfig LuckWheelConfig
var groupCustomThemeConfig GroupCustomThemeConfig
var giftConfig GiftConfig
var dailyConfig DailyConfig
var fruitTycoonConfig FruitTycoonConfig
var activityConfig ActivityConfig
var checkoutConfig CheckoutConfig
var riskControl RiskControlConfig
var payerMaxConfig PayerMaxConfig
var mode string
var master bool
var sudConfig SudConfig
var urlConfig URLConfig
func GetConfigMysql() MysqlConfig {
return mysqlConfigData
}
func GetConfigMysqlCode() MysqlCodeConfig {
return mysqlCodeConfigData
}
func GetConfigRedis() RedisConfig {
return redisConfigData
}
func GetConfigJWT() JwtConfig {
return jwtConfigData
}
func GetConfigGameJWT() GameJwtConfig {
return userJwtConfigData
}
func GetConfigApp() AppConfig {
return appConfigData
}
func GetConfigOss() OssConfig {
return ossConfigData
}
func GetConfigAws() AwsConfig {
return awsConfigData
}
func GetConfigGooglePay() GooglePayConfig {
return googlePayData
}
func GetMode() string {
return mode
}
func AppIsRelease() bool {
return GetMode() == RELEASE
}
func AppIsLocal() bool {
return GetMode() == LOCAL
}
func IsMaster() bool {
return master
}
func GetOssCDN() string {
return ossConfigData.OSS_CDN
}
func GetRongyunAppKey() string {
return rongyunData.RONG_CLOUD_APP_KEY
}
func GetRongyunAppSecret() string {
return rongyunData.RONG_CLOUD_APP_SECRET
}
func GetRongyunUrl() string {
return rongyunData.RONG_CLOUD_URL
}
func GetTencentyunAppId() int {
return tencentyunData.TENCENTYUN_APP_ID
}
func GetTencentyunKey() string {
return tencentyunData.TENCENTYUN_KEY
}
func GetTxOverSeaAppId() int {
return tencentyunData.TX_OVERSEA_APP_ID
}
func GetTxOverSeaAppKey() string {
return tencentyunData.TX_OVERSEA_KEY
}
func GetEmasRegionId() string {
return emasData.REGION_ID
}
func GetEmasAccessKeyId() string {
return emasData.ACCESS_KEY_ID
}
func GetEmasAccessKeySecret() string {
return emasData.ACCESS_KEY_SECRET
}
func GetEmasAndroidAppKey() string {
return emasData.ANDROID_APP_KEY
}
func GetEmasIosAppKey() string {
return emasData.IOS_APP_KEY
}
func GetEmasApns() string {
return emasData.APNS
}
func GetAgoraAppId() string {
return agora.APP_ID
}
func GetAgoraAppCertificate() string {
return agora.APP_CERTIFICATE
}
func GetAgoraCustomerKey() string {
return agora.CUSTOMER_KEY
}
func GetAgoraCustomerSecret() string {
return agora.CUSTOMER_SECRET
}
func GetMatchConfig() *MatchConfig {
return &matchData
}
func GetOnlineConfig() *OnlineConfig {
return &onlineData
}
func GetSessionConfig() SessionConfig {
return sessionData
}
func GetVideoConfig() VideoConfig {
return videoData
}
func GetBeanConfig() BeanConfig {
return beanData
}
func GetH5Config() H5Config {
return h5Data
}
func GetGroupImConfig() GroupImConfig {
return groupImData
}
func GetGradeConfig() GradeConfig {
return gradeData
}
func GetLikeConfig() LikeConfig {
return likeData
}
func GetApplePayConfig() ApplePayConfig {
return applePayData
}
func GetRegisterConfig() RegisterConfig {
return registerData
}
func GetBannerConfig() BannerConfig {
return bannerConfig
}
func GetDiamondConfig() DiamondConfig {
return diamondConfig
}
func GetLuckyWheelConfig() LuckWheelConfig {
return luckyWheelConfig
}
func GetGroupCustomThemeConfig() GroupCustomThemeConfig {
return groupCustomThemeConfig
}
func GetGiftConfig() GiftConfig {
return giftConfig
}
func GetDailyConfig() DailyConfig {
return dailyConfig
}
func GetFruitTycoonConfig() FruitTycoonConfig {
return fruitTycoonConfig
}
func GetActivityConfig() ActivityConfig {
return activityConfig
}
func GetCheckoutConfig() CheckoutConfig {
return checkoutConfig
}
func GetRiskControlConfig() RiskControlConfig {
return riskControl
}
func GetPayerMaxConfig() PayerMaxConfig {
return payerMaxConfig
}
func GetSudConfig() SudConfig {
return sudConfig
}
func GetUrlConfig() URLConfig {
return urlConfig
}
func init() {
str, _ := os.Getwd()
mylogrus.MyLog.Info(str)
envDir := ".env"
//加载环境变量
if err := godotenv.Load(envDir); err != nil {
mylogrus.MyLog.Fatalf("Error loading .env err:%v", err)
}
//获取环境变量
mode = os.Getenv("MODE")
var err error
master, _ = strconv.ParseBool(os.Getenv("MASTER"))
mylogrus.MyLog.Infof("My role is %t", master)
iniDir := mode + ".ini"
if runtime.GOOS == "darwin" { // mac本地调试
iniDir = "/var/log/hilo/" + iniDir
}
//根据环境变量获取具体的配置,实现多环境配置
//var conf *ini.File
conf, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, iniDir)
if err != nil {
mylogrus.MyLog.Fatal(err)
}
//加载mysql的配置
if err := conf.Section("DATABASE").MapTo(&mysqlConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DATABASECODE").MapTo(&mysqlCodeConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("REDIS").MapTo(&redisConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("JWT").MapTo(&jwtConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GAMEJWT").MapTo(&userJwtConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("APP").MapTo(&appConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
mylogrus.MyLog.Infof("APP: %+v", appConfigData)
}
if err := conf.Section("OSS").MapTo(&ossConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("AWS").MapTo(&awsConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if awsConfigData.CONFIDENCE <= 50 {
awsConfigData.CONFIDENCE = 80
}
mylogrus.MyLog.Infof("AWS: %+v", awsConfigData)
}
if err := conf.Section("RONGYUN").MapTo(&rongyunData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("TENCENTYUN").MapTo(&tencentyunData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
mylogrus.MyLog.Info("TENCENTYUN: ", tencentyunData)
}
if err := conf.Section("EMAS").MapTo(&emasData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("AGORA").MapTo(&agora); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("MATCH").MapTo(&matchData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("ONLINE").MapTo(&onlineData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("SESSION").MapTo(&sessionData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("VIDEO").MapTo(&videoData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("BEAN").MapTo(&beanData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("H5").MapTo(&h5Data); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GROUPIM").MapTo(&groupImData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GRADE").MapTo(&gradeData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("LIKE").MapTo(&likeData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("APPLEPAY").MapTo(&applePayData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("REGISTER").MapTo(&registerData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("BANNER").MapTo(&bannerConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DIAMOND").MapTo(&diamondConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if diamondConfig.NEW_USER_INVITE_AWARD <= 0 {
diamondConfig.NEW_USER_INVITE_AWARD = 5000
}
}
if err := conf.Section("LUCKY_WHEEL").MapTo(&luckyWheelConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GROUP_CUSTOM_THEME").MapTo(&groupCustomThemeConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GIFT").MapTo(&giftConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DAILY").MapTo(&dailyConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("CHECKOUT").MapTo(&checkoutConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("PAYER_MAX").MapTo(&payerMaxConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("FRUIT_TYCOON").MapTo(&fruitTycoonConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
// 防止未配置或配置错误
if fruitTycoonConfig.BIG_WINNER_LOW <= 0 {
fruitTycoonConfig.BIG_WINNER_LOW = 10000
}
if fruitTycoonConfig.BIG_WINNER_HIGH <= 0 {
fruitTycoonConfig.BIG_WINNER_HIGH = 20000
}
if fruitTycoonConfig.POOL_RATIO <= 0 || fruitTycoonConfig.POOL_RATIO > 100 {
fruitTycoonConfig.POOL_RATIO = 20
}
if fruitTycoonConfig.WATERMELON_RATIO <= 0 || fruitTycoonConfig.WATERMELON_RATIO > 100 {
fruitTycoonConfig.WATERMELON_RATIO = 70
}
mylogrus.MyLog.Infof("FRUIT_TYCOON: %+v", fruitTycoonConfig)
}
if err := conf.Section("ACTIVITY").MapTo(&activityConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
// 防止未配置或配置错误
if activityConfig.COUNTRY_STAR_POOL_RATIO <= 0 {
activityConfig.COUNTRY_STAR_POOL_RATIO = 20
}
if activityConfig.COUNTRY_STAR_ORDINARY_RATIO <= 0 {
activityConfig.COUNTRY_STAR_ORDINARY_RATIO = 20
}
mylogrus.MyLog.Infof("ACTIVITY: %+v", activityConfig)
}
if err := conf.Section("RISK_CONTROL").MapTo(&riskControl); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if riskControl.USER_QPS_LIMIT <= 0 {
riskControl.USER_QPS_LIMIT = 128
}
if riskControl.USER_URL_QPS_LIMIT <= 0 {
riskControl.USER_URL_QPS_LIMIT = 64
}
mylogrus.MyLog.Infof("RISK_CONTROL: %+v", riskControl)
}
if err := conf.Section("SUD").MapTo(&sudConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("URL").MapTo(&urlConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
}
package consul
import (
"fmt"
"github.com/hashicorp/consul/api"
"hilo-user/_const"
"hilo-user/mylogrus"
"net/http"
"os"
"time"
)
const (
RegisterName = "hiloUser"
RegisterTag = "用户中心"
)
// 异步注册到consul
func RegisterToConsul(port int) {
go register(port, false)
go selfCheck(port)
}
func consulCheck(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintln(w, "consulCheck")
}
func register(port int, retry bool) {
client, err := api.NewClient(api.DefaultConfig()) //非默认情况下需要设置实际的参数
if err != nil {
mylogrus.MyLog.Errorf("RegisterToConsul Fail:%v", err)
return
}
if client == nil {
mylogrus.MyLog.Errorf("Fail to get consul client.")
return
}
mylogrus.MyLog.Infof("RegisterToConsul:%v-%v", client, err)
checkPort := port + 1000
registration := new(api.AgentServiceRegistration)
hostName, _ := os.Hostname()
registration.ID = fmt.Sprintf("%s-%s", RegisterName, hostName)
registration.Name = RegisterName
registration.Port = port
registration.Tags = []string{RegisterTag}
myIp, myNodeName := "", ""
if localIp, err := _const.GetClientIp(); err != nil {
mylogrus.MyLog.Fatalln("local ip not found", err)
} else {
myIp = localIp
}
mylogrus.MyLog.Infof("My ip is %s, nodeName: %s\n", myIp, myNodeName)
registration.Address = myIp
registration.Check = &api.AgentServiceCheck{
HTTP: fmt.Sprintf("http://localhost:%d%s", checkPort, "/check"),
Timeout: "3s",
Interval: "5s",
DeregisterCriticalServiceAfter: "30s", //check失败后30秒删除本服务
}
err = client.Agent().ServiceRegister(registration)
if err != nil {
mylogrus.MyLog.Errorf("register server error :%v ", err)
return
}
if !retry {
http.HandleFunc("/check", consulCheck)
if err = http.ListenAndServe(fmt.Sprintf(":%d", checkPort), nil); err != nil {
mylogrus.MyLog.Warnf("check server error :%v ", err)
return
}
}
}
// 自愈检查
// 启动后每一分钟检查一次
// 首次启动不执行
func selfCheck(port int) {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
client, err := api.NewClient(api.DefaultConfig()) //非默认情况下需要设置实际的参数
if err != nil {
mylogrus.MyLog.Errorf("RegisterToConsul Fail:%v", err)
break
}
if client == nil {
mylogrus.MyLog.Errorf("Fail to get consul client.")
break
}
cataLog := client.Catalog()
if cataLog == nil {
mylogrus.MyLog.Errorf("No catalog.")
break
}
services, _, err := cataLog.Service(RegisterName, "", nil)
if err != nil {
mylogrus.MyLog.Errorf("%v", err)
break
}
if len(services) == 0 {
mylogrus.MyLog.Errorf("%s not found.", RegisterName)
go register(port, true) // 重新注册
} else {
mylogrus.MyLog.Infof("%s check success %v", RegisterName, services[0])
}
}
}
}
package consul
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/api/watch"
"hilo-user/mylogrus"
"sync"
)
type ServiceCallback func(serviceStatus map[string]map[string][]string) // service->status->addrs
// 定义watcher
type Watcher struct {
Address string // consul agent 的地址:"127.0.0.1:8500"
Wp *watch.Plan // 总的Services变化对应的Plan
watchers map[string]*watch.Plan // 对已经进行监控的service作个记录
RWMutex *sync.RWMutex
}
// 将consul新增的service加入,并监控
func (w *Watcher) registerServiceWatcher(serviceName string, callback ServiceCallback) error {
// watch endpoint 的请求参数,具体见官方文档:https://www.consul.io/docs/dynamic-app-config/watches#service
wp, err := watch.Parse(map[string]interface{}{
"type": "service",
"service": serviceName,
})
if err != nil {
return err
}
// 定义service变化后所执行的程序(函数)handler
wp.Handler = func(idx uint64, data interface{}) {
switch d := data.(type) {
case []*consulapi.ServiceEntry:
var serviceStatus = make(map[string]map[string][]string)
for _, i := range d {
if data, ok := serviceStatus[i.Service.Service]; ok {
data[i.Checks.AggregatedStatus()] = append(data[i.Checks.AggregatedStatus()], fmt.Sprintf("%s:%d", i.Service.Address, i.Service.Port))
} else {
serviceStatus[i.Service.Service] = make(map[string][]string)
serviceStatus[i.Service.Service][i.Checks.AggregatedStatus()] = append(serviceStatus[i.Service.Service][i.Checks.AggregatedStatus()],
fmt.Sprintf("%s:%d", i.Service.Address, i.Service.Port))
}
}
// 回传到外面
callback(serviceStatus)
mylogrus.MyLog.Infof("consul service status: %s", serviceStatus)
}
}
// 启动监控
go wp.Run(w.Address)
// 对已启动监控的service作一个记录
w.RWMutex.Lock()
w.watchers[serviceName] = wp
w.RWMutex.Unlock()
return nil
}
func newWatcher(watchType string, opts map[string]string, consulAddr string, callback ServiceCallback) (*Watcher, error) {
var options = map[string]interface{}{
"type": watchType,
}
// 组装请求参数。(监控类型不同,其请求参数不同)
for k, v := range opts {
options[k] = v
}
wp, err := watch.Parse(options)
if err != nil {
return nil, err
}
w := &Watcher{
Address: consulAddr,
Wp: wp,
watchers: make(map[string]*watch.Plan),
RWMutex: new(sync.RWMutex),
}
wp.Handler = func(idx uint64, data interface{}) {
switch d := data.(type) {
// 这里只实现了对services的监控,其他监控的data类型判断参考:https://github.com/dmcsorley/avast/blob/master/consul.go
// services
case map[string][]string:
for i := range d {
// 如果该service已经加入到ConsulRegistry的services里监控了,就不再加入 或者i 为 "consul"的字符串
// 为什么会多一个consul,参考官方文档services监听的返回值:https://www.consul.io/docs/dynamic-app-config/watches#services
if _, ok := w.watchers[i]; ok || i == "consul" {
continue
}
w.registerServiceWatcher(i, callback)
}
// 从总的services变化中找到不再监控的service并停止
w.RWMutex.RLock()
watches := w.watchers
w.RWMutex.RUnlock()
// remove unknown services from watchers
for i, svc := range watches {
if _, ok := d[i]; !ok {
svc.Stop()
delete(watches, i)
}
}
default:
mylogrus.MyLog.Errorf("不能判断监控的数据类型: %v", &d)
}
}
return w, nil
}
func RegisterWatcher(watchType string, opts map[string]string, consulAddr string, callback ServiceCallback) error {
w, err := newWatcher(watchType, opts, consulAddr, callback)
if err != nil {
mylogrus.MyLog.Error(err)
return err
}
defer w.Wp.Stop()
if err = w.Wp.Run(consulAddr); err != nil {
mylogrus.MyLog.Errorf("RegisterWatcher err: %v", err)
return err
}
return nil
}
package mysql
import "time"
type EntityI interface {
GetID() ID
//用于判断数据是否进行持久化
IsLazyLoad() bool
//默认值为false true:代表要移除数据
CheckDel() bool
//检查是否唯一键冲突,依旧更新
CheckOnDuplicateKeyUPDATE() bool
//检查是否唯一键冲突,则不插入
CheckOnDuplicateKeyIGNORE() bool
//更新乐观锁 默认值为false true:乐观锁更新
CheckUpdateVersion() bool
//更新条件.
CheckUpdateCondition() bool
//获取版本号
GetUpdateVersionBefore() uint
//更新情况
GetUpdateCondition() string
//save 动作排除字段
GetOmit() []string
}
type Entity struct {
ID ID `gorm:"primary_key"`
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
lazyLoad bool `gorm:"-"`
del bool `gorm:"-"`
onDuplicateKeyUPDATE bool `gorm:"-"`
onDuplicateKeyIGNORE bool `gorm:"-"`
updateVersionFlag bool `gorm:"-"`
updateVersionBefore uint `gorm:"-"`
updateCondition string `gorm:"-"`
omit []string `gorm:"-"` //更新排除
updateColumns map[string]interface{} `gorm:"-"` //更新字段
}
func (t *Entity) GetID() ID {
return t.ID
}
func (t *Entity) IsLazyLoad() bool {
return t.lazyLoad
}
func (t *Entity) SetLasyLoad() {
t.lazyLoad = true
}
func (t *Entity) SetDel() {
t.del = true
}
func (t *Entity) CheckDel() bool {
return t.del
}
func (t *Entity) SetOnDuplicateKeyUPDATE() {
t.onDuplicateKeyUPDATE = true
}
func (t *Entity) SetOnDuplicateKeyIGNORE() {
t.onDuplicateKeyIGNORE = true
}
func (t *Entity) CheckOnDuplicateKeyUPDATE() bool {
return t.onDuplicateKeyUPDATE
}
func (t *Entity) CheckOnDuplicateKeyIGNORE() bool {
return t.onDuplicateKeyIGNORE
}
func (t *Entity) SetCheckUpdateVersionBefore(versionBefore uint) {
t.updateVersionBefore = versionBefore
t.updateVersionFlag = true
}
func (t *Entity) SetCheckUpdateCondition(condition string) {
t.updateCondition = condition
}
func (t *Entity) CheckUpdateVersion() bool {
return t.updateVersionFlag
}
func (t *Entity) CheckUpdateCondition() bool {
return t.updateCondition != ""
}
func (t *Entity) GetUpdateCondition() string {
return t.updateCondition
}
func (t *Entity) GetUpdateVersionBefore() uint {
return t.updateVersionBefore
}
func (t *Entity) GetOmit() []string {
return t.omit
}
func (t *Entity) SetOmit(omit []string) {
t.omit = omit
}
func (t *Entity) SetUpdateColumns(updateColumns map[string]interface{}) {
t.updateColumns = updateColumns
}
func (t *Entity) GetUpdateColumns() map[string]interface{} {
return t.updateColumns
}
package mysql
import (
"context"
"fmt"
. "gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"time"
)
func MyNew(writer Writer, config Config) Interface {
var (
infoStr = "%s[info] "
warnStr = "%s[warn] "
errStr = "%s[error] "
traceStr = "%s[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s[%.3fms] [rows:%v] %s"
)
//if config.Colorful {
// infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset
// warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
// errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
// traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
// traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
// traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
//}
myTraceStr := " traceId:%v userId:%v"
infoStr += myTraceStr
warnStr += myTraceStr
errStr += myTraceStr
traceStr += myTraceStr
traceWarnStr += myTraceStr
traceErrStr += myTraceStr
return &myLogger{
Writer: writer,
Config: config,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
type myLogger struct {
Writer
Config
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
}
// LogMode log mode
func (l *myLogger) LogMode(level LogLevel) Interface {
newlogger := *l
newlogger.LogLevel = level
return &newlogger
}
// Info print info
func (l myLogger) Info(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Info {
l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Warn print warn messages
func (l myLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Warn {
l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Error print error messages
func (l myLogger) Error(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Error {
l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Trace print sql message
func (l myLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
traceId, userId := ctx.Value("traceId"), ctx.Value("userId")
if l.LogLevel > Silent {
elapsed := time.Since(begin)
switch {
case err != nil && l.LogLevel >= Error:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
if rows == -1 {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case l.LogLevel == Info:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
}
}
}
package mysql
import (
"fmt"
_ "github.com/go-sql-driver/mysql" //加载mysql驱动
_ "github.com/joho/godotenv/autoload"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"log"
"net/url"
"time"
)
var Db *gorm.DB
func init() {
var err error
mysqlConfigData := config.GetConfigMysql()
options := "?charset=utf8mb4&parseTime=True&loc=Local&time_zone=" + url.QueryEscape("'+8:00'")
dsn := "" + mysqlConfigData.MYSQL_USERNAME + ":" + mysqlConfigData.MYSQL_PASSWORD + "@(" + mysqlConfigData.MYSQL_HOST + ")/" + mysqlConfigData.MYSQL_DB + options
sqlLogger := logger.Default.LogMode(logger.Info)
if file := mylogrus.GetSqlLog(); file != nil {
//sqlLogger = logger.New(log.New(file, "\r\n", log.Ldate|log.Lmicroseconds), logger.Config{
sqlLogger = MyNew(log.New(file, "", log.Ldate|log.Lmicroseconds), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Info,
Colorful: false,
})
}
Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: sqlLogger,
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
log.Fatalf("mysql connect error %v", err)
} else {
log.Println("mysql connect success")
}
if Db.Error != nil {
fmt.Printf("database error %v", Db.Error)
}
if d, err := Db.DB(); err == nil {
d.SetConnMaxLifetime(time.Minute * 30) // 连接可复用的最大时间。
d.SetMaxIdleConns(20) // 空闲连接数
d.SetMaxOpenConns(20) // 最大连接数
}
}
package mysql
import "strconv"
/**
基于PDM,建立统计的数据domain结构。注意,不要选择0, 因为go的int默认值为0
*/
//主键ID
type ID = uint64
//性别
type Sex = uint8
//加减
type AddReduce = uint8
//拥有
type YesNo = uint8
//短描述
type Str = string
//时间戳
type Time = int64
//状态
type UserYesNo = uint8
//平台
type Platform = uint8
//多枚举类型
type Type = uint8
//数量
type Num = uint32
//时间戳
type Timestamp = uint64
//排序
type Index = uint16
//数量,并且用到-1作为特殊标记位
type NumAll = int
//开启关闭
type OpenClose = uint8
//逻辑删除
type LogicDel = uint8
//设备
type Device = uint8
type PeriodType = uint8
type FinishYesNo = uint8
//性别
const (
MAN Sex = 1
WOMAN Sex = 2
EMPTY Sex = 0
)
//yes no
const (
YES YesNo = 1
NO YesNo = 2
)
const (
OPEN OpenClose = 1
CLOSE OpenClose = 2
)
//加,减
const (
ADD AddReduce = 1
REDUCE AddReduce = 2
NilAddREDUCE AddReduce = 3
)
const (
USER UserYesNo = 1
NOUSER UserYesNo = 2
)
func TypeToString(t Type) string {
return strconv.Itoa(int(t))
}
package redisCli
import (
"context"
"github.com/go-redis/redis/v8"
"hilo-user/mylogrus"
"hilo-user/resource/config"
)
var RedisClient *redis.Client
func init() {
RedisClient = redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 0, // use default DB
PoolSize: 20,
MinIdleConns: 20,
})
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_HOST)
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_PASSWORD)
pong, err := RedisClient.Ping(context.Background()).Result()
if err != nil {
mylogrus.MyLog.Warn(err)
mylogrus.MyLog.Fatal("redis db0 connect fail")
} else {
mylogrus.MyLog.Info("redis db0 connection success - ", pong)
}
}
func GetRedis() *redis.Client {
return RedisClient
}
...@@ -2,10 +2,11 @@ package resp ...@@ -2,10 +2,11 @@ package resp
import ( import (
"encoding/json" "encoding/json"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/req"
"net/http" "net/http"
) )
...@@ -15,6 +16,7 @@ type Response struct { ...@@ -15,6 +16,7 @@ type Response struct {
MessageData interface{} `json:"messageData"` // 消息详情 MessageData interface{} `json:"messageData"` // 消息详情
OperationMessage interface{} `json:"operationMessage"` // 操作消息 OperationMessage interface{} `json:"operationMessage"` // 操作消息
Data interface{} `json:"data"` // 数据 Data interface{} `json:"data"` // 数据
Edata interface{} `json:"edata"` // 加密数据
} }
type GameResponse struct { type GameResponse struct {
...@@ -36,34 +38,67 @@ func ResponseOk(c *gin.Context, data interface{}) { ...@@ -36,34 +38,67 @@ func ResponseOk(c *gin.Context, data interface{}) {
Code: myerr.GetSuccessCode(), Code: myerr.GetSuccessCode(),
Message: myerr.GetSuccessMsg(), Message: myerr.GetSuccessMsg(),
OperationMessage: myerr.GetSuccessMsg(), OperationMessage: myerr.GetSuccessMsg(),
Data: data, }
if _, ok := c.Get(mycontext.InnerEncrypt); ok {
//response.Edata = utils.EncryptionData(data, []byte("484194d4d0f968a7"))
response.Edata = utils.EncryptionData(data, []byte("hilo!@#$%^&*()_+"))
} else {
response.Data = data
} }
printResponseBody(c, &response) printResponseBody(c, &response)
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
func GameResponseOk(c *gin.Context, data interface{}) { // 分页返回
// always return http.StatusOK // 客户端入参 req.PageReqBase
response := GameResponse{ // 服务端返回 req.PageRespBase
RetCode: 0, func ResponsePageBaseOk(c *gin.Context, data interface{}, nextPageIndex int, hasNextPage bool) {
RetMsg: myerr.GetSuccessMsg(), if data == nil {
SdkErrorCode: 0, data = make([]interface{}, 0)
}
pageData := req.PageRespBase{
NextPageIndex: nextPageIndex,
HasNextPage: hasNextPage,
Data: data, Data: data,
} }
printResponseBody(c, &response) response := Response{
Code: myerr.GetSuccessCode(),
Message: myerr.GetSuccessMsg(),
OperationMessage: myerr.GetSuccessMsg(),
}
if _, ok := c.Get(mycontext.InnerEncrypt); ok {
//response.Edata = utils.EncryptionData(data, []byte("484194d4d0f968a7"))
response.Edata = utils.EncryptionData(pageData, []byte("hilo!@#$%^&*()_+"))
} else {
response.Data = pageData
}
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
func GameResponseFail(c *gin.Context, err *myerr.GameError) { // 分页返回
// always return http.StatusOK // 客户端入参 req.PageReqBase
response := GameResponse{ // 服务端返回 req.PageRespBase
RetCode: err.Code(), func ResponsePageOk(c *gin.Context, data interface{}, total int64, pageSize, pageIndex int) {
RetMsg: err.Error(), if data == nil {
SdkErrorCode: err.Code(), data = make([]interface{}, 0)
Data: nil, }
nextPageIndex := 0
hasNextPage := false
if (pageIndex-1)*pageSize+pageSize-1 < int(total) {
nextPageIndex = pageIndex + 1
hasNextPage = true
}
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) c.JSON(http.StatusOK, response)
} }
...@@ -113,13 +148,13 @@ func ResponseErrWithString(c *gin.Context, msg interface{}) { ...@@ -113,13 +148,13 @@ func ResponseErrWithString(c *gin.Context, msg interface{}) {
} }
func printResponseBody(c *gin.Context, response interface{}) { func printResponseBody(c *gin.Context, response interface{}) {
traceId, _ := c.Get(_const.TRACEID) traceId, _ := c.Get(mycontext.TRACEID)
if _traceId, ok := traceId.(string); ok { if _traceId, ok := traceId.(string); ok {
c.Header("X-Trace-ID", _traceId) c.Header("X-Trace-ID", _traceId)
} }
var userId uint64 = 0 var userId uint64 = 0
if strUserId, ok := c.Get(_const.USERID); ok { if strUserId, ok := c.Get(mycontext.USERID); ok {
userId = strUserId.(uint64) userId = strUserId.(uint64)
} }
......
package cp_r
import (
"git.hilo.cn/hilo-common/_const/enum/timezone_e"
"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, 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, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
loc := timezone_e.GetFixedTimezone(c.GetHeader(mycontext.TIMEZONE))
if loc == nil {
user, err := user_m.GetUser(model, userId)
if err != nil {
return myCtx, err
}
if user.Language == "ar" {
loc = timezone_e.KSATimezoneLoc
}
}
var response = make([]cp_cv.CvCpAnniversary, 0)
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, lang)
for _, v := range anniversary {
timestamp := v.Timestamp
if v.Type >= cp_e.AnniversaryItemTypeBirthday1 && timestamp > 0 {
timestamp = cp_m.CalcNextAnniversary(timestamp, loc)
}
// 客户端只认识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"
"git.hilo.cn/hilo-common/utils"
"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
}
appVersion, deviceType := c.GetHeader(mycontext.APP_VERSION), c.GetHeader(mycontext.DEVICETYPE)
if deviceType == "android" {
if lower, _ := utils.CompareVersion(appVersion, fmt.Sprintf("<= %s", "3.9.0")); lower {
pageReq.PageSize = 30
}
}
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: user_cv.UserBaseToUserLittle(userBase[rank.UserId1]),
User2: user_cv.UserBaseToUserLittle(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: user_cv.UserBaseToUserLittle(userBase[rank.UserId1]),
User2: user_cv.UserBaseToUserLittle(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: user_cv.UserBaseToUserLittle(userBase[rank.UserId1]),
User2: user_cv.UserBaseToUserLittle(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 = user_cv.UserBaseToUserLittle(userBases[relation.UserId1])
}
if relation.UserId2 > 0 {
response.User2 = user_cv.UserBaseToUserLittle(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/_const/enum/timezone_e"
"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
}
var model = domain.CreateModelContext(myContext)
userInfo, err := user_m.GetUser(model, userId)
if err != nil {
return myContext, err
}
loc := timezone_e.GetFixedTimezone(c.GetHeader(mycontext.TIMEZONE))
if loc == nil {
if userInfo.Language == "ar" {
loc = timezone_e.KSATimezoneLoc
}
}
externalId := c.Query("externalId")
if len(externalId) <= 0 {
return myContext, bizerr.InvalidParameter
}
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, loc)
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
}
package route package route
import ( import (
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/req" "hilo-user/req"
"hilo-user/resource/config"
"hilo-user/resp" "hilo-user/resp"
) )
...@@ -30,17 +29,14 @@ func wrapper(handler HandlerFunc) func(c *gin.Context) { ...@@ -30,17 +29,14 @@ func wrapper(handler HandlerFunc) func(c *gin.Context) {
if myContext == nil { if myContext == nil {
myContext = mycontext.CreateMyContext(nil) myContext = mycontext.CreateMyContext(nil)
} }
c.Set(_const.ACTION_RESULt, true) c.Set(mycontext.ACTION_RESULt, true)
if err != nil { if err != nil {
c.Set(_const.ACTION_RESULt, false) c.Set(mycontext.ACTION_RESULt, false)
reqUri := c.Request.RequestURI reqUri := c.Request.RequestURI
method := c.Request.Method method := c.Request.Method
userId, _ := req.GetUserId(c) userId, _ := req.GetUserId(c)
switch h := err.(type) { 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: case *myerr.BusinessError:
myContext.Log.Warnf("request err -> url:%v, method:%v, userId:%v, err :%+v\n", reqUri, method, userId, h.GetErr()) myContext.Log.Warnf("request err -> url:%v, method:%v, userId:%v, err :%+v\n", reqUri, method, userId, h.GetErr())
resp.ResponseBusiness(c, h) resp.ResponseBusiness(c, h)
......
package invite_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"github.com/jinzhu/now"
"hilo-user/cv/invite_cv"
"hilo-user/domain/cache/user_c"
"hilo-user/domain/model/invite_m"
"hilo-user/domain/model/promotion_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"time"
)
// @Tags 新人邀请
// @Summary 提交申请
// @Param newUserCode formData string true "被邀请人id"
// @Param platform formData string true "平台"
// @Param platformId formData string true "平台Id"
// @Param recharge formData string true "充值金额"
// @Param userCode formData string true "邀请人id"
// @Param videoUrl formData string true "充值金额"
// @Success 200
// @Router /v2/user/invite/apply [post]
func InviteApply(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
type paramStr struct {
NewUserCode string `form:"newUserCode" binding:"required"`
Platform string `form:"platform" binding:"required"`
PlatformId string `form:"platformId" binding:"required"`
Recharge string `form:"recharge" binding:"required"`
UserCode string `form:"userCode" binding:"required"`
VideoUrl string `form:"videoUrl" binding:"required"`
}
myUserId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
// 每日最多提交10次
noLimitTimesMap := map[uint64]struct{}{1770691: {}, 2264431: {}, 7283111: {}}
if _, ok := noLimitTimesMap[myUserId]; !ok {
// 今日提交次数
times, err := invite_m.TodayInviteApplyCount(model, myUserId)
if err != nil {
model.Log.Errorf("InviteApply myUserId:%v, err:%v", myUserId, err)
return myCtx, err
}
if times >= 15 {
return myCtx, bizerr.InviteApplyTimes
}
}
var param paramStr
if err := c.ShouldBind(&param); err != nil {
return myCtx, err
}
// 平台是否填写正确
platforms := promotion_m.GetPromotionPlatforms(model)
var existsPlatform bool
for _, v := range platforms {
if v == param.Platform {
existsPlatform = true
}
}
if !existsPlatform {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, bizerr.InvalidParameter
}
// code 是否存在
newUser, err := user_m.GetUserByCode(model, param.NewUserCode)
if err != nil {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, bizerr.InviteApplyNewCodeInvalid
}
user, err := user_m.GetUserByCode(model, param.UserCode)
if err != nil {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, bizerr.InviteApplyCodeInvalid
}
//if user.ID != myUserId { //只能自己提交
// return myCtx, bizerr.InvalidParameter
//}
if newUser.ID == 0 || user.ID == 0 {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, bizerr.InvalidParameter
}
// 邀请人是否有资格邀请
if !promotion_m.IsPromotionAgent(model, user.ID) {
model.Log.Errorf("InviteApply 没有邀请资格 param:%v", param)
return myCtx, bizerr.InviteApplyNoPermission
}
//if user.ID != myUserId && !promotion_m.IsMyPromotionManager(model, user.ID, myUserId) {
// model.Log.Errorf("InviteApply 没有邀请资格 param:%v", param)
// return myCtx, bizerr.InviteApplyNoPermission
//}
// 被邀请人是否已经被人提交过申请
isApply, err := invite_m.IsInInviteApply(model, newUser.ID)
if err != nil {
model.Log.Errorf("InviteApply param:%v, err:%v", param, err)
return myCtx, err
}
if isApply {
model.Log.Errorf("InviteApply 已经被别人邀请过了 param:%v", param)
return myCtx, bizerr.InviteApplyAlreadyInvited
}
// 被邀请人是否符合条件
isInvite, err := promotion_m.IsPromotionInvitee(model, newUser.ID)
if err != nil {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, err
}
if isInvite {
model.Log.Errorf("InviteApply 已经被别人邀请了 param:%v", param)
return myCtx, bizerr.InviteApplyAlreadyInvited
}
// 插入邀请表
err = invite_m.CreateInviteApply(model, user.ID, newUser.ID, myUserId, param.Platform, param.PlatformId, param.Recharge, param.VideoUrl)
if err != nil {
model.Log.Errorf("InviteApply param:%v", param)
return myCtx, err
}
resp.ResponseOk(c, nil)
return myCtx, nil
}
// @Tags 新人邀请
// @Summary 查询历史申请
// @Param pageIndex query int true "偏移值 默认:1" default(1)
// @Param pageSize query int true "请求数量 默认:10" default(10)
// @Param beginTime query string true "开始时间2006-01-02"
// @Param endTime query string true "结束时间2006-01-02"
// @Param type query int true "1.已申请2.待审核3.已通过4.已拒绝"
// @Success 200 {object} invite_cv.InviteApplyRes
// @Router /v2/user/invite/apply [get]
func InviteApplyList(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
type paramStr struct {
PageIndex int `form:"pageIndex" binding:"required"`
PageSize int `form:"pageSize" binding:"required"`
BeginTime time.Time `form:"beginTime" binding:"required" time_format:"2006-01-02"`
EndTime time.Time `form:"endTime" binding:"required" time_format:"2006-01-02"`
Type int `form:"type"`
}
var param paramStr
if err := c.ShouldBindQuery(&param); err != nil {
return myCtx, err
}
if param.Type < 0 || param.Type > 4 {
return myCtx, bizerr.InvalidParameter
}
//beginTime, err := time.ParseInLocation(utils.DATE_FORMAT, param.BeginTime, time.Local)
//if err != nil {
// return nil, myerr.WrapErr(err)
//}
//endTime, err := time.ParseInLocation(utils.DATE_FORMAT, param.EndTime, time.Local)
//if err != nil {
// return nil, myerr.WrapErr(err)
//}
param.EndTime = utils.GetDayEndTime(param.EndTime)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
var model = domain.CreateModelContext(myCtx)
agentIds := []uint64{userId}
if promotion_m.IsPromotionManager(model, userId) {
agentIds, err = promotion_m.GetPromotionManagerAgentList(model, userId)
if err != nil {
return myCtx, err
}
}
if param.Type == 0 { // 返回所有Type类型有多少条数
user, err := user_c.GetUserTinyById(model, userId)
if err != nil {
model.Log.Errorf("GetApplyList param:%v, err:%v", param, err)
return myCtx, bizerr.InvalidParameter
}
numList := make([]*invite_cv.InviteApplyNumRes, 0, 4)
for _, gType := range []int{1, 2, 3, 4} { // 1.已申请2.待审核3.已通过4.已拒绝
num, err := invite_m.GetInviteApplyNumByType(model, gType, param.BeginTime, param.EndTime, agentIds, userId)
if err != nil {
return myCtx, err
}
numList = append(numList, &invite_cv.InviteApplyNumRes{Type: gType, Num: num})
}
resp.ResponsePageOk(c, &invite_cv.InviteApplyRes{NumList: numList, MyCode: user.Code}, 0, 0, 0)
return myCtx, nil
}
list, total, err := invite_m.GetApplyList(model, userId, agentIds, param.PageIndex, param.PageSize, param.Type, param.BeginTime, param.EndTime)
if err != nil {
model.Log.Errorf("GetApplyList param:%v, err:%v", param, err)
return myCtx, err
}
uids := make([]uint64, 0, len(list)+1)
for _, v := range list {
uids = append(uids, v.UserId, v.NewUserId)
}
users, err := user_c.GetUserTinyMap(model, uids, true)
if err != nil {
model.Log.Errorf("GetApplyList param:%v, err:%v", param, err)
return myCtx, err
}
res := &invite_cv.InviteApplyRes{}
res.List = make([]*invite_cv.InviteApply, 0, len(list))
for _, v := range list {
res.List = append(res.List, &invite_cv.InviteApply{
NewUserCode: users[v.NewUserId].Code,
Platform: v.Platform,
Recharge: v.RechargeInfo,
UserCode: users[v.UserId].Code,
CreateUnix: v.CreatedTime.Unix(),
Level: v.Level,
Status: v.Status,
Avatar: users[v.NewUserId].Avatar,
ExternalId: users[v.NewUserId].ExternalId,
Reason: v.Reason,
Country: users[v.NewUserId].Country,
PlatformId: v.PlatformId,
})
}
resp.ResponsePageOk(c, res, total, param.PageSize, param.PageIndex)
return myCtx, nil
}
// @tags 新人邀请
// @Summary 平台列表
// @Success 200 {object} []string
// @Router /v2/user/invite/platform [get]
func PromotionPlatform(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
resp.ResponseOk(c, []string{"Falla", "Yalla", "Whisper", "Ahlan", "Mashi", "YoYo", "Yoho", "Echo", "Hawa",
"Yalla Ludo", "Hafla", "Imo", "Ola Party", "ShareChat", "Viya", "Hello Yo", "Bigo Live", "Hago", "Oye Talk", "Tiktok", "Bigo", "Mr7ba"})
return myCtx, nil
}
// @Tags 新人邀请
// @Summary 查询周期
// @Success 200 {object} invite_cv.AgentPeriod
// @Router /v2/user/invite/period [get]
func AgentPeriod(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var response invite_cv.AgentPeriod
week := now.BeginningOfWeek().AddDate(0, 0, 1) // 周一开始
for i := 0; i < 12; i++ {
response.Week = append(response.Week, invite_cv.AgentPeriodWeek{
StartDate: week.Format("2006-01-02"),
EndDate: week.AddDate(0, 0, 6).Format("2006-01-02"),
})
week = week.AddDate(0, 0, -7)
}
resp.ResponseOk(c, response)
return myCtx, nil
}
...@@ -2,17 +2,20 @@ package route ...@@ -2,17 +2,20 @@ package route
import ( import (
"bytes" "bytes"
"crypto/md5"
"fmt"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"hilo-user/mylogrus"
"hilo-user/req" "hilo-user/req"
"hilo-user/req/jwt" "hilo-user/req/jwt"
"hilo-user/resource/config"
"hilo-user/resp" "hilo-user/resp"
"io/ioutil" "io/ioutil"
"runtime/debug" "runtime/debug"
"strconv"
"strings" "strings"
"time" "time"
) )
...@@ -78,8 +81,8 @@ func JWTApiHandle(c *gin.Context) { ...@@ -78,8 +81,8 @@ func JWTApiHandle(c *gin.Context) {
} }
} }
c.Set(_const.USERID, claims.UserId) c.Set(mycontext.USERID, claims.UserId)
c.Set(_const.EXTERNAL_ID, claims.ExternalId) c.Set(mycontext.EXTERNAL_ID, claims.ExternalId)
c.Writer.Header().Add("token", newToken) c.Writer.Header().Add("token", newToken)
c.Next() c.Next()
...@@ -91,18 +94,24 @@ func LoggerHandle(c *gin.Context) { ...@@ -91,18 +94,24 @@ func LoggerHandle(c *gin.Context) {
start := time.Now() start := time.Now()
clientIp := c.ClientIP() clientIp := c.ClientIP()
method := c.Request.Method method := c.Request.Method
traceId := genTraceId() traceId := genTraceId(c)
reqUri := c.Request.RequestURI reqUri := c.Request.RequestURI
c.Set(_const.TRACEID, traceId) c.Set(mycontext.TRACEID, traceId)
// //
header := c.Request.Header header := c.Request.Header
//类型 //类型
devicetype := header.Get("Devicetype") devicetype := header.Get("Devicetype")
c.Set(_const.DEVICETYPE, devicetype) c.Set(mycontext.DEVICETYPE, devicetype)
appVersion := header.Get("Appversion") appVersion := header.Get("Appversion")
c.Set(_const.APP_VERSION, appVersion) c.Set(mycontext.APP_VERSION, appVersion)
c.Set(_const.URL, reqUri) c.Set(mycontext.URL, reqUri)
c.Set(_const.METHOD, method) 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) userId, _ := req.GetUserId(c)
...@@ -128,3 +137,66 @@ func LoggerHandle(c *gin.Context) { ...@@ -128,3 +137,66 @@ func LoggerHandle(c *gin.Context) {
latency := end.Sub(start) latency := end.Sub(start)
mycontext.CreateMyContext(c.Keys).Log.Infof("request end fullPath:%v,url:%v, method: %v, traceId:%v, latency:%v userId:%v", c.FullPath(), reqUri, method, traceId, latency, userId) mycontext.CreateMyContext(c.Keys).Log.Infof("request end fullPath:%v,url:%v, method: %v, traceId:%v, latency:%v userId:%v", c.FullPath(), reqUri, method, traceId, latency, userId)
} }
// 加密Handle
func EncryptHandle(c *gin.Context) {
header := c.Request.Header
appVersion := header.Get("Appversion")
if len(appVersion) > 0 {
if high, _ := utils.CompareVersion(appVersion, "> 3.9.0"); high {
c.Set(mycontext.InnerEncrypt, true)
}
}
c.Next()
}
//http信息解密(web)
func HttpWebSecretHandle(c *gin.Context) {
traceId, _ := c.Keys[mycontext.TRACEID]
timestamp := c.GetHeader("timestamp") //时间戳,单位秒
nonce := c.GetHeader("nonce") //随机数字
signature := c.GetHeader("signature") //sha1加密结果
mylogrus.MyLog.Debugf("handle secret begin timestamp:%v, nonce:%v, signature:%v traceId:%v", timestamp, nonce, signature, traceId)
if nonce == "hilo" {
mylogrus.MyLog.Infof("no check http secret handle")
} else {
if timestamp == "" || nonce == "" || signature == "" {
resp.ResponseBusiness(c, bizerr.HttpSecret)
c.Abort()
return
}
timestampInt, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
resp.ResponseBusiness(c, bizerr.HttpSecret)
c.Abort()
return
}
nowTimestamp := time.Now().Unix()
v := nowTimestamp - timestampInt
//10分钟内有效,改成60分钟,20210402产品让我改成60分钟,原因:依旧有用户时间戳不对,达到了30分钟
if v < -60*60 || v > 60*60 {
mylogrus.MyLog.Warnf("handle secret err, timestampInt:%v, nowTimestamp:%v, v:%v, traceId:%v", timestampInt, nowTimestamp, v, traceId)
//2021/11/05 产品让我关的,因为中东用户时间戳有问题
/* ResponseBusiness(c, bizerr.HttpSecret)
c.Abort()
return*/
}
str := timestamp + config.GetConfigApp().WEB_SECRET + nonce
//避免web的暴露,让用户知道app的api加密方式。
h := md5.New()
//h := sha1.New()
h.Write([]byte(str))
newSignature := fmt.Sprintf("%x", h.Sum(nil))
//newSignature := string(sha1.New().Sum([]byte(str))[:])
if signature != newSignature {
mylogrus.MyLog.Errorf("handle secret err signature:%v, newSignature:%v, traceId:%v", signature, newSignature, traceId)
resp.ResponseBusiness(c, bizerr.HttpSecret)
c.Abort()
return
}
}
c.Next()
}
package recommend_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/cv/user_cv"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/recommend_m"
"hilo-user/domain/model/user_m"
"hilo-user/resp"
)
type RecommendUser struct {
User *user_cv.UserTiny `json:"user"`
CurrentRoom string `json:"currentRoom"` // 当前用户所在房间(产品叫“群组”)
}
// @Tags 用户推荐
// @Summary 推荐最近送礼的50人,最近12小时赠送礼物大于100k的用户
// @Param token header string true "token"
// @Success 200 {object} []RecommendUser
// @Router /v1/recommend/user/gift [get]
func UserRecommendGift(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
model := domain.CreateModelContext(myContext)
// 获取推荐
recommendUser := recommend_m.GetPastTop50SendGiftUsers(model)
var response = make([]RecommendUser, 0)
if len(recommendUser) <= 0 {
resp.ResponseOk(c, response)
return myContext, nil
}
var userIds []mysql.ID
for _, v := range recommendUser {
userIds = append(userIds, v.SendUserId)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myContext, err
}
rooms, err := group_m.RoomLivingUserIdFilter(model, userIds)
if err != nil {
return nil, err
} else if len(rooms) > 0 {
// to txGroupIds
var imGroupIds []string
for _, imGroupId := range rooms {
imGroupIds = append(imGroupIds, imGroupId)
}
txGroupIdsMap, _ := group_m.ToTxGroupIdMap(model, imGroupIds)
for uid, room := range rooms {
rooms[uid] = txGroupIdsMap[room]
}
}
for _, v := range recommendUser {
response = append(response, RecommendUser{user_cv.UserToTiny(users[v.SendUserId]), rooms[v.SendUserId]})
}
resp.ResponseOk(c, response)
return myContext, nil
}
package redis_r
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"hilo-user/domain"
"hilo-user/mycontext"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"strconv"
"strings"
"time"
)
var stop = make(chan struct{})
var match = "match_relation_*"
func Scan(c *gin.Context) (*mycontext.MyContext, error) {
go func() {
return
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
cursor := uint64(0)
first := true
var err error
var keys []string
for first || cursor != 0 {
first = false
select {
case <-stop:
return
default:
keys, cursor, err = model.Redis.Scan(model, cursor, match, 1000).Result()
if err != nil {
model.Log.Errorf("SCAN fail:%v", err)
return
}
var delKeys []string
for _, key := range keys {
arr := strings.Split(key, "_")
if len(arr) == 4 {
cycle, _ := strconv.ParseInt(arr[2], 10, 64)
if cycle > 0 && cycle < 208933198 { // 2022-12-20号
delKeys = append(delKeys, key)
}
}
}
if len(delKeys) > 0 {
cnt, err := model.Redis.Del(model, keys...).Result()
model.Log.Infof("del redis keys:%v,cnt:%v,err:%v", delKeys, cnt, err)
}
time.Sleep(time.Second)
}
}
}()
return mycontext.CreateMyContext(nil), nil
}
func ScanStop(c *gin.Context) (*mycontext.MyContext, error) {
return nil, nil
myCtx := mycontext.CreateMyContext(c.Keys)
stop <- struct{}{}
return myCtx, nil
}
func Hscan(c *gin.Context) (*mycontext.MyContext, error) {
RedisClient := redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 1, // use default DB
PoolSize: 20,
MinIdleConns: 20,
})
cursor := uint64(0)
first := true
var err error
var keys []string
for first || cursor != 0 {
first = false
select {
case <-stop:
return nil, nil
default:
keys, cursor, err = RedisClient.HScan(context.Background(), "user", cursor, "*", 1000).Result()
if err != nil {
return nil, err
}
l := len(keys)
if l%2 != 0 {
mylogrus.MyLog.Errorf("Hscan keys err:%v", keys)
continue
}
for i := 0; i < len(keys); i += 2 {
if !strings.Contains(keys[i+1], "172.26.95.48:50050") && !strings.Contains(keys[i+1], "172.26.95.24:50050") {
res, err := RedisClient.HDel(context.Background(), "user", keys[i]).Result()
msg := fmt.Sprintf("hdel user %v,value:%v,res:%v,err:%v", keys[i], keys[i+1], res, err)
mylogrus.MyLog.Infof("%v", msg)
}
}
}
}
return nil, nil
}
package route package route
import ( import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger" ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles" "github.com/swaggo/gin-swagger/swaggerFiles"
"hilo-user/_const/enum/msg_e"
_ "hilo-user/docs" _ "hilo-user/docs"
"hilo-user/route/redis_r" "hilo-user/domain/model/msg_m"
"hilo-user/resp"
"hilo-user/route/cp_r"
"hilo-user/route/invite_r"
"hilo-user/route/recommend_r"
"hilo-user/route/user_r" "hilo-user/route/user_r"
) )
...@@ -17,19 +25,81 @@ func InitRouter() *gin.Engine { ...@@ -17,19 +25,81 @@ func InitRouter() *gin.Engine {
needLogin := r.Group("") needLogin := r.Group("")
needLogin.Use(ExceptionHandle, LoggerHandle, JWTApiHandle) needLogin.Use(ExceptionHandle, LoggerHandle, JWTApiHandle)
v1 := needLogin.Group("/v1") v1 := needLogin.Group("/v1")
v2 := needLogin.Group("/v2")
user := v1.Group("/user") user := v1.Group("/user")
{ {
user.GET("/nameplate", wrapper(user_r.UserNameplate)) user.GET("/nameplate", wrapper(user_r.UserNameplate))
user.GET("/bag/:resType", wrapper(user_r.UserBag))
user.GET("/detail", EncryptHandle, wrapper(user_r.UserDetail))
user.GET("/detail/:userExternalId", EncryptHandle, wrapper(user_r.UserDetailByExternalId))
}
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))
}
recommend := v1.Group("recommend")
{
recommend.GET("/user/gift", wrapper(recommend_r.UserRecommendGift))
}
userV2 := v2.Group("/user")
{
userV2.POST("/invite/apply", wrapper(invite_r.InviteApply))
userV2.GET("/invite/apply", wrapper(invite_r.InviteApplyList))
userV2.GET("/invite/platform", wrapper(invite_r.PromotionPlatform))
userV2.GET("/invite/period", wrapper(invite_r.AgentPeriod))
userV2.GET("/detail/room", EncryptHandle, wrapper(user_r.GetUserDetailInRoom))
} }
inner := r.Group("/inner") inner := r.Group("/inner")
inner.Use(ExceptionHandle, LoggerHandle) inner.Use(ExceptionHandle, LoggerHandle)
//} innerUser := inner.Group("/user")
test := r.Group("/test") {
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))
innerUser.GET("/cp/entryEffect", wrapper(user_r.GetUserCpEntryEffect)) // 获取cp进场特效信息,高频接口,需要额外处理
innerUser.GET("/svipNobleLevel", wrapper(user_r.MGetUserSvipNobleLevel)) // 获取用户svip/noble/level等信息
}
// 道具相关
innerProp := inner.Group("/prop")
{ {
//test.GET("/user", wrapper(user_r.Test)) innerProp.POST("/bag/send", wrapper(user_r.SendUserBag)) // 下发背包道具,暂礼物
test.GET("/scan/redis", wrapper(redis_r.Scan)) innerProp.POST("/noble/send", wrapper(user_r.SendUserNoble)) // 下发贵族
test.GET("/hscan/redis", wrapper(redis_r.Hscan)) innerProp.POST("/headwear/send", wrapper(user_r.SendUserHeadwear)) // 下发头饰
test.GET("/scan/redis/stop", wrapper(redis_r.ScanStop)) innerProp.POST("/ride/send", wrapper(user_r.SendUserRide)) // 下发座驾
} }
r.GET("/test", wrapper(Test))
return r return r
} }
func Test(c *gin.Context) (*mycontext.MyContext, error) {
var model = domain.CreateModelContext(nil)
myCtx := mycontext.CreateMyContext(c.Keys)
// 下发hilo小助手通知
if err := msg_m.NewUserRecord(model, 4549, msg_e.AddProps, "", 0, "", fmt.Sprintf("%d", 10), "https://image.whoisamy.shop/hilo/manager/1b95e0e63b814261acccc6e1f1736627.png", "", "").Persistent(); err != nil {
model.Log.Errorf("NewUserRecord fail")
} else {
msg_m.SendEmasMsgAssistant(model, "f98c7fe5698e447c998615332eb660d1", "iOS")
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
package user_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/_const/enum/res_e"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/bag_m"
"hilo-user/domain/model/res_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"strconv"
"time"
)
// @Tags 用户背包
// @Summary 获取用户的背包
// @Param resType path int true "类型:1 礼物"
// @Success 200 {object} []user_cv.UserBag
// @Router /v1/user/bag/{resType} [get]
func UserBag(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
resType, err := strconv.Atoi(c.Param("resType"))
if err != nil {
return myCtx, err
}
var results []user_cv.UserBag
switch res_e.ResUserBag(resType) {
case res_e.ResUserBagGift:
userBagGifts, err := bag_m.GetUserValidUserBag(model, userId, res_e.ResUserBagGift)
if err != nil {
return myCtx, err
}
allGifts, err := res_m.FindAllResGiftsMap(model)
if err != nil {
return myCtx, err
}
for _, bagGift := range userBagGifts {
if gift, ok := allGifts[bagGift.ResId]; ok {
info := user_cv.UserBag{
BagId: bagGift.ID,
ResType: res_e.ResUserBagGift,
ResId: gift.ID,
GiftId: gift.ID,
Name: gift.Name,
DiamondNum: gift.DiamondNum,
IconUrl: gift.IconUrl,
SvgaUrl: gift.SvagUrl,
Count: bagGift.Count,
RemainDays: int(bagGift.EndTime.Sub(time.Now()).Hours() / 24),
HasGiftText: gift.HasGiftText,
}
if gift.ID == cp_e.CpConfessionGiftId || gift.HasGiftText { // 如果是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"},
&user_cv.TextStyle{TextColor: "#FFFFFF", TextSize: 40, TextKey: "gift_text"},
)
}
results = append(results, info)
}
}
default:
return myCtx, bizerr.InvalidParameter
}
resp.ResponseOk(c, results)
return myCtx, nil
}
package user_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/cv/noble_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain/cache/user_c"
"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"
"hilo-user/resp"
"time"
)
type MGetUserLevelReq struct {
Ids []mysql.ID `form:"ids" binding:"required"`
}
// @Tags 用户-内部
// @Summary 批量获取用户等级
// @Param ids query string true "用户id,如:ids=1&ids=2&ids=3"
// @Success 200 {object} user_cv.MGetUserLevelData
// @Router /inner/user/levels [get]
func MGetUserLevels(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req MGetUserLevelReq
if err := c.ShouldBindQuery(&req); err != nil {
return myCtx, err
}
wealthGrade, err := user_m.MGetWealthGrade(model, req.Ids)
if err != nil {
return myCtx, err
}
charmGrade, err := user_m.MGetCharmGrade(model, req.Ids)
activeGrade, err := user_m.MGetActiveGrade(model, req.Ids)
nobleLevel, err := noble_m.BatchGetNobleLevel(model, req.Ids)
response := user_cv.MGetUserLevelData{}
for _, userId := range req.Ids {
response[userId] = user_cv.CvUserLevel{
UserId: userId,
WealthUserGrade: wealthGrade[userId],
CharmUserGrade: charmGrade[userId],
ActiveUserGrade: activeGrade[userId],
NobleLevel: nobleLevel[userId],
}
}
resp.ResponseOk(c, response)
return myCtx, nil
}
type MGetUserSvipVipLevelReq struct {
Ids []mysql.ID `form:"ids" binding:"required"`
}
// @Tags 用户-内部
// @Summary 批量获取用户等级
// @Param ids query string true "用户id,如:ids=1&ids=2&ids=3"
// @Success 200 {object} user_cv.CvUserDetail
// @Router /inner/user/svipNobleLevel [get]
func MGetUserSvipNobleLevel(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req MGetUserLevelReq
if err := c.ShouldBindQuery(&req); err != nil {
return myCtx, err
}
wealthGrade, err := user_m.MGetWealthGrade(model, req.Ids)
if err != nil {
return myCtx, err
}
charmGrade, err := user_m.MGetCharmGrade(model, req.Ids)
activeGrade, err := user_m.MGetActiveGrade(model, req.Ids)
nobleLevel, err := noble_m.BatchGetNobleLevel(model, req.Ids)
svip, err := rpc.MGetUserSvip(model, req.Ids)
users, err := user_m.GetUserMapByIds(model, req.Ids)
response := make(map[uint64]user_cv.CvUserDetail)
for _, userId := range req.Ids {
user := users[userId]
response[userId] = user_cv.CvUserDetail{
CvUserBase: user_cv.CvUserBase{
Id: &user.ID,
Avatar: &user.Avatar,
ExternalId: &user.ExternalId,
Nick: &user.Nick,
Sex: &user.Sex,
Country: &user.Country,
CountryIcon: &user.CountryIcon,
Code: &user.Code,
Birthday: &user.Birthday,
Svip: rpc.CvSvip{
SvipLevel: svip[userId].SvipLevel,
},
Noble: noble_cv.CvNoble{
Level: nobleLevel[userId],
},
},
WealthUserGrade: wealthGrade[userId],
CharmUserGrade: charmGrade[userId],
ActivityUserGrade: activeGrade[userId],
}
}
resp.ResponseOk(c, response)
return myCtx, nil
}
type GetUserBagReq struct {
BagId mysql.ID `form:"bagId" binding:"required"`
}
// @Tags 用户-内部
// @Summary 获取单个背包
// @Param bagId query int true "背包id"
// @Success 200 {object} user_cv.UserBag
// @Router /inner/user/bag/id [get]
func GetUserBagId(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req GetUserBagReq
if err := c.ShouldBindQuery(&req); err != nil {
return myCtx, err
}
bag, err := bag_m.GetUserBag(model, req.BagId)
if err != nil {
return myCtx, err
}
gift, err := res_m.FindResGift(model, bag.ResId)
if err != nil {
return myCtx, err
}
resp.ResponseOk(c, user_cv.UserBag{
BagId: bag.ID,
ResType: bag.ResType,
ResId: bag.ResId,
GiftId: bag.ResId,
Name: gift.Name,
DiamondNum: gift.DiamondNum,
IconUrl: gift.IconUrl,
SvgaUrl: gift.SvagUrl,
Count: bag.Count,
RemainDays: int(bag.EndTime.Sub(time.Now()).Hours() / 24),
})
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 := cp_cv.GetTranslate(237, req.Language)
if msgId, ok := cp_e.CpLevelTitle[level.Level]; ok {
title = cp_cv.GetTranslate(msgId, req.Language)
}
var oldScore uint32
if oldCp, _ := cp_m.GetOldConnectCp(model, cpRelation.UserId1, cpRelation.UserId2); oldCp != nil {
oldScore = uint32(oldCp.Score)
}
response = cp_cv.CvCp{
CpUserInfo: userBases[cpUserId],
CpLevel: cp_cv.CvCpLevel{
Level: cpLevel,
Points: oldScore + cp_m.SumCpPoints(model, cpRelation.Id), // 历史分数
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
}
// @Tags 用户-内部
// @Summary 获取用户cpEffect
// @Param id query int true "用户id"
// @Param language query string true "语言"
// @Success 200 {object} cp_cv.CvCpEntryEffect
// @Router /inner/user/cp/entryEffect [get]
func GetUserCpEntryEffect(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.CvCpEntryEffect
cpLevel := cp_e.CpLevel0
cpRelation, exists := cp_m.GetCpRelation(model, userId)
if !exists {
resp.ResponseOk(c, response)
return myContext, nil
}
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
}
response.CpLevel = cpLevel
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]
}
}
// 二级以上才有进场特效
if cpLevel >= cp_e.CpLevel2 {
for _, v := range privilegeList {
if v.Type == cp_e.CpPrivilegeRoomEffect && v.UserSwitch {
response.CpEntryEffect = true
}
}
}
if cpUser, _ := user_c.GetUserTinyById(model, cpUserId); cpUser != nil {
response.CpUserAvatar = cpUser.Avatar
}
resp.ResponseOk(c, response)
return myContext, nil
}
package user_r
import (
"errors"
"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/domain/model/bag_m"
"hilo-user/domain/service/headwear_s"
"hilo-user/domain/service/noble_s"
"hilo-user/domain/service/ride_s"
"hilo-user/resp"
)
type SendUserBagReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
ResType mysql.Type `form:"resType" binding:"required"` // 道具类型 1:礼物道具
ResId mysql.ID `form:"resId" binding:"required"` // 道具资源id
Count mysql.Num `form:"count" binding:"min=1"` // 下发数量
Day int `form:"day" binding:"min=1"` // 天数
Reason string `form:"reason" binding:"required"` // 原因
}
// @Tags 用户-内部
// @Summary 发送背包道具
// @Param userId formData int true "用户id"
// @Param resType formData int true "道具类型 1:礼物道具"
// @Param resId formData int true "道具资源id"
// @Param count formData int true "下发数量"
// @Param day formData int true "天数"
// @Param reason formData string true "原因"
// @Success 200
// @Router /inner/prop/bag/send [post]
func SendUserBag(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req SendUserBagReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
//var bagId mysql.ID
var err error
switch req.ResType {
case mysql.Type(1):
if _, err = bag_m.AddUserBag(model, req.UserId, req.ResType, req.ResId, req.Count, req.Day, req.Reason); err != nil {
return myCtx, err
}
default:
return myCtx, errors.New("un support type")
}
//userBag, err := bag_m.GetUserBag(model, bagId)
//if err != nil {
// return myCtx, err
//}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserNobleReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
Level uint16 `form:"level" binding:"min=1,max=5"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户贵族
// @Param userId formData int true "用户id"
// @Param level formData int true "贵族等级"
// @Param day formData int true "下发天数"
// @Success 200
// @Router /inner/prop/noble/send [post]
func SendUserNoble(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserNobleReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := noble_s.NewNobleService(myCtx).SendNoble(req.UserId, req.Level, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserHeadwearReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
HeadwearId mysql.ID `form:"headwearId" binding:"required"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户头饰
// @Param userId formData int true "用户id"
// @Param headwearId formData int true "头饰id"
// @Param day formData int true "天数"
// @Success 200
// @Router /inner/prop/headwear/send [post]
func SendUserHeadwear(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserHeadwearReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := headwear_s.NewHeadwearService(myCtx).SendHeadwear(req.UserId, req.HeadwearId, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserRideReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
RideId mysql.ID `form:"rideId" binding:"required"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户座驾
// @Param userId formData int true "用户id"
// @Param rideId formData int true "座驾id"
// @Param day formData int true "天数"
// @Success 200
// @Router /inner/prop/ride/send [post]
func SendUserRide(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserRideReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := ride_s.NewRideService(myCtx).SendRide(req.UserId, req.RideId, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
package user_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/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
)
type ReturnUserNameplatePublic struct {
Id uint64 `json:"id"`
Name string `json:"name"`
PicUrl string `json:"picUrl"`
SvgaUrl string `json:"svgaUrl"`
//类型 (0:代表自身就是一种类型 > 0, 一种相关联的类型)
//Type res_m2.ResMedalType `json:"type"`
//
//IsHas bool `json:"isHas"`
}
// @Tags 用户
// @Summary 获取用户的铭牌
// @Param code query string false "用户code,不传则获取自己的"
// @Success 200 {object} ReturnUserNameplatePublic
// @Router /v1/user/nameplate [get]
func UserNameplate(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
code := c.Query("code")
if code != "" {
u, err := user_m.GetUserByCode(model, code)
if err != nil {
return myContext, myerr.WrapErr(err)
}
if u.ID <= 0 {
return myContext, bizerr.InvalidParameter
}
userId = u.ID
}
//所有的勋章
var resNameplates []res_m.ResNameplate
if err := mysql.Db.Model(&res_m.ResNameplate{}).Order("sort asc, type asc, threshold asc").Find(&resNameplates).Error; err != nil {
return myContext, myerr.WrapErr(err)
}
resNameplateIds := make([]mysql.ID, 0, len(resNameplates))
for _, r := range resNameplates {
resNameplateIds = append(resNameplateIds, r.ID)
}
//获取用户的
var userNameplates []user_m.UserNameplate
if err := mysql.Db.Model(&user_m.UserNameplate{}).Where(&user_m.UserNameplate{
UserId: userId,
}).Where("(end_time >= NOW() or end_time is null)").Find(&userNameplates).Error; err != nil {
return myContext, myerr.WrapErr(err)
}
//转换成map
userNameplateMap := make(map[uint32]struct{})
for _, r := range userNameplates {
userNameplateMap[r.NameplateId] = struct{}{}
}
results := make([]ReturnUserNameplatePublic, 0, len(resNameplates))
for i, r := range resNameplates {
if _, flag := userNameplateMap[uint32(r.ID)]; flag {
results = append(results, ReturnUserNameplatePublic{
Id: resNameplates[i].ID,
Name: resNameplates[i].Name,
PicUrl: resNameplates[i].PicUrl,
SvgaUrl: resNameplates[i].SvgaUrl,
//Type: resNameplates[i].Type,
//IsHas: true,
})
}
}
resp.ResponseOk(c, results)
return myContext, nil
}
package user_r package user_r
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-user/domain" "hilo-user/_const/redis_key/user_k"
"hilo-user/domain/model/res_m" "hilo-user/cv/user_cv"
"hilo-user/domain/model/user_m" "hilo-user/domain/model/group_m"
"hilo-user/mycontext" "hilo-user/domain/model/tim_m"
"hilo-user/myerr" "hilo-user/domain/service/user_s"
"hilo-user/myerr/bizerr"
"hilo-user/req" "hilo-user/req"
"hilo-user/resource/mysql"
"hilo-user/resp" "hilo-user/resp"
"time"
) )
type ReturnUserNameplatePublic struct { // @Tags 用户
Id uint64 `json:"id"` // @Summary 获取用户详细信息
Name string `json:"name"` // @Param token header string true "token"
PicUrl string `json:"picUrl"` // @Param timestamp header string true "时间戳"
SvgaUrl string `json:"svgaUrl"` // @Param nonce header string true "随机数字"
//类型 (0:代表自身就是一种类型 > 0, 一种相关联的类型) // @Param signature header string true "sha1加密结果"
//Type res_m2.ResMedalType `json:"type"` // @Param deviceType header string true "系统类型 ios android"
// // @Param deviceVersion header string true "系统版本"
//IsHas bool `json:"isHas"` // @Success 200 {object} user_cv.CvUserDetail
// @Router /v1/user/detail [get]
func UserDetail(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
cvUserDetail, err := user_s.NewUserService(myContext).GetUserDetail(userId, userId, lang)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, cvUserDetail)
return myContext, nil
} }
// @Tags 用户 // @Tags 用户
// @Summary 获取用户的铭牌 // @Summary 获取用户详细信息
// @Param code query string false "用户code,不传则获取自己的" // @Param token header string true "token"
// @Success 200 {object} ReturnUserNameplatePublic // @Param timestamp header string true "时间戳"
// @Router /v1/user/nameplate [get] // @Param nonce header string true "随机数字"
func UserNameplate(c *gin.Context) (*mycontext.MyContext, error) { // @Param signature header string true "sha1加密结果"
// @Param deviceType header string true "系统类型 ios android"
// @Param deviceVersion header string true "系统版本"
// @Param userExternalId path string true "userExternalId"
// @Param groupId query string false "群组id,当传了该id,则返回该用户在该群组的身份"
// @Success 200 {object} user_cv.CvUserDetail
// @Router /v1/user/detail/{userExternalId} [get]
func UserDetailByExternalId(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys) myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c) userId, lang, err := req.GetUserIdLang(c, myContext)
if err != nil { if err != nil {
return myContext, err return myContext, err
} }
otherUserId, err := req.ToUserId(myContext, mysql.Str(c.Param("userExternalId")))
if err != nil {
return nil, err
}
model := domain.CreateModelContext(myContext) model := domain.CreateModelContext(myContext)
code := c.Query("code") imGroupId := c.Query("groupId")
if code != "" { if imGroupId != "" {
u, err := user_m.GetUserByCode(model, code) imGroupId, err = group_m.ToImGroupId(model, imGroupId)
if err != nil { if err != nil {
return myContext, myerr.WrapErr(err) return myContext, err
}
}
cvUserDetail, err := user_s.NewUserService(myContext).GetUserDetail(otherUserId, userId, lang)
if err != nil {
return myContext, err
} }
if u.ID <= 0 { if imGroupId != "" {
return myContext, bizerr.InvalidParameter cvUserDetail.GroupRole, err = group_m.GetGroupRoleById(model, imGroupId, otherUserId)
if err != nil {
return myContext, err
} }
userId = u.ID
} }
//所有的勋章 if cvUserDetail != nil {
var resNameplates []res_m.ResNameplate // 检查是否需要同步
if err := mysql.Db.Model(&res_m.ResNameplate{}).Order("sort asc, type asc, threshold asc").Find(&resNameplates).Error; err != nil { if n, err := redisCli.GetRedis().Exists(model, user_k.GetKeySyncTimHilo(userId)).Result(); err == nil {
return myContext, myerr.WrapErr(err) if n == 0 {
// FIXME:转异步执行
err = tim_m.FlushHiloInfo(*cvUserDetail.ExternalId, cvUserDetail.IsVip, cvUserDetail.IsPrettyCode,
cvUserDetail.Medals, cvUserDetail.MyGroupPowerName, cvUserDetail.Noble.Level)
if err == nil {
redisCli.GetRedis().Set(model, user_k.GetKeySyncTimHilo(userId), "1", time.Minute)
} else {
model.Log.Info("UserBaseByExternalId, FlushHiloInfo failed: ", err)
}
} else {
model.Log.Info("UserDetailByExternalId, no need to sync yet: ", userId)
}
} else {
model.Log.Info("UserDetailByExternalId, check KeySyncTimHilo failed", err)
} }
resNameplateIds := make([]mysql.ID, 0, len(resNameplates))
for _, r := range resNameplates {
resNameplateIds = append(resNameplateIds, r.ID)
} }
//获取用户的 resp.ResponseOk(c, cvUserDetail)
var userNameplates []user_m.UserNameplate return myContext, nil
if err := mysql.Db.Model(&user_m.UserNameplate{}).Where(&user_m.UserNameplate{ }
UserId: userId,
}).Where("(end_time >= NOW() or end_time is null)").Find(&userNameplates).Error; err != nil { // @Tags 用户
return myContext, myerr.WrapErr(err) // @Summary 房间内获取用户信息
} // @Param userExternalId query string true "userExternalId"
//转换成map // @Param groupId query string false "群组id,当传了该id,则返回该用户在该群组的身份"
userNameplateMap := make(map[uint32]struct{}) // @Success 200 {object} user_cv.CvUserDetailRoom
for _, r := range userNameplates { // @Router /v2/user/detail/room [get]
userNameplateMap[r.NameplateId] = struct{}{} func GetUserDetailInRoom(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
otherUserId, err := req.ToUserId(myContext, c.Query("userExternalId"))
if err != nil {
return nil, err
} }
model := domain.CreateModelContext(myContext)
results := make([]ReturnUserNameplatePublic, 0, len(resNameplates)) imGroupId := c.Query("groupId")
for i, r := range resNameplates { if imGroupId != "" {
if _, flag := userNameplateMap[uint32(r.ID)]; flag { imGroupId, err = group_m.ToImGroupId(model, imGroupId)
results = append(results, ReturnUserNameplatePublic{ if err != nil {
Id: resNameplates[i].ID, return myContext, err
Name: resNameplates[i].Name, }
PicUrl: resNameplates[i].PicUrl, }
SvgaUrl: resNameplates[i].SvgaUrl,
//Type: resNameplates[i].Type, cvUserDetail, err := user_s.NewUserService(myContext).GetUserDetail(otherUserId, userId, lang)
//IsHas: true, if err != nil {
}) return myContext, err
}
if imGroupId != "" {
cvUserDetail.GroupRole, err = group_m.GetGroupRoleById(model, imGroupId, otherUserId)
if err != nil {
return myContext, err
}
}
if cvUserDetail != nil {
// 检查是否需要同步
if n, err := redisCli.GetRedis().Exists(model, user_k.GetKeySyncTimHilo(userId)).Result(); err == nil {
if n == 0 {
// FIXME:转异步执行
err = tim_m.FlushHiloInfo(*cvUserDetail.ExternalId, cvUserDetail.IsVip, cvUserDetail.IsPrettyCode,
cvUserDetail.Medals, cvUserDetail.MyGroupPowerName, cvUserDetail.Noble.Level)
if err == nil {
redisCli.GetRedis().Set(model, user_k.GetKeySyncTimHilo(userId), "1", time.Minute)
} else {
model.Log.Info("UserBaseByExternalId, FlushHiloInfo failed: ", err)
}
} else {
model.Log.Info("UserDetailByExternalId, no need to sync yet: ", userId)
}
} else {
model.Log.Info("UserDetailByExternalId, check KeySyncTimHilo failed", err)
} }
} }
resp.ResponseOk(c, results) resp.ResponseOk(c, user_cv.CvUserDetailToCvUserDetailRoom(cvUserDetail))
return myContext, nil return myContext, nil
} }
package route package route
import ( import (
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"strings" "strings"
) )
func genTraceId() string { func genTraceId(c *gin.Context) string {
if trace := c.GetHeader(mycontext.TRACEID); len(trace) > 0 {
return trace
}
traceId := strings.Replace(uuid.NewV4().String(), "-", "", -1) traceId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
traceId = traceId[:len(traceId)/2] traceId = traceId[:len(traceId)/2]
return traceId return traceId
......
MODE=local
package test
import (
"git.hilo.cn/hilo-common/_const/enum/timezone_e"
"git.hilo.cn/hilo-common/domain"
"hilo-user/domain/model/cp_m"
"testing"
"time"
)
func TestInitCpAnniversary(t *testing.T) {
err := cp_m.InitCpAnniversary(domain.CreateModelNil(), cp_m.CpRelation{
Id: 1,
UserId1: 7642,
UserId2: 4549,
}, "ar")
println(err)
}
func TestCalcNextAnniversary(t *testing.T) {
t2 := cp_m.CalcNextAnniversary(1686211996, time.Local)
println(t2)
}
func TestCalLoc(t *testing.T) {
loc := timezone_e.GetFixedTimezone("GMT+8")
println(time.Now().In(loc).Format("2006-01-02 15:04:05"))
loc = timezone_e.GetFixedTimezone("GMT+3")
println(time.Now().In(loc).Format("2006-01-02 15:04:05"))
loc = timezone_e.GetFixedTimezone("GMT+5")
println(time.Now().In(loc).Format("2006-01-02 15:04:05"))
}
func TestSumCpScore(t *testing.T) {
model := domain.CreateModelNil()
old, err := cp_m.GetOldConnectCp(model, 7642, 4549)
t.Logf("%v-%v", old, err)
n := cp_m.SumCpPoints(model, 1)
t.Logf("%v", n)
}
[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