Commit d6a0473c authored by hujiebin's avatar hujiebin

feat:提交回家做

parent b17c2009
package bean_e
import "git.hilo.cn/hilo-common/resource/mysql"
type StatusAccount = mysql.Type
const (
Normal StatusAccount = 1
//冻结,只是限制减少,不限制增加
Frozen StatusAccount = 2
)
type OperateType = mysql.Type
const (
//接受礼物
ReceiveGift OperateType = 1
//钻石兑换
DiamondExchange OperateType = 2
//管理人删除
MgrReduce OperateType = 3
//1对1视频收益
VideoMinute OperateType = 4
//匹配送礼物加时间
MatchTime OperateType = 5
//MatchGift
MatchGift OperateType = 6
//VideoGift
VideoGift OperateType = 7
//视频时间获取豆子汇总
VideoTimeTotal OperateType = 8
// 粉钻相关
PinkReceiveGift OperateType = 9 // 收礼物得金币
PinkDiamondExchange OperateType = 10 // 换成粉钻
PinkMgrReduce OperateType = 11 // 管理人扣减金币
PinkVideoMinute OperateType = 12 // 1对1视频金币收益(不显示)
PinkMatchTime OperateType = 13 // 匹配送粉钻礼物加时间
PinkMatchGift OperateType = 14 // 匹配粉钻礼物
PinkVideoGift OperateType = 15 // 1对1视频粉钻礼物
PinkVideoTimeTotal OperateType = 16 // 1对1(粉钻)时间汇总(显示)
)
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 diamond_e
import "git.hilo.cn/hilo-common/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 //加入群组,群主得黄钻
Paypal OperateType = 68 //paypal充值
)
type PayVerifyStatus = mysql.Type
const (
//检查之前
VerifyBefore PayVerifyStatus = 1
//成功
VerifySuccess PayVerifyStatus = 2
)
package fruitMachine_e
const MaxFruitId = 8
const MaxFruitStakeCount = 6 // 最多可以下注多少种水果
const RoundTime = 5 // 多少分钟为一轮
const RecycleRate = 50 // 上一轮流转到下一次的比例(%)
const WatermelonFruitId = 8 // 西瓜ID
type FruitMachineStatus = uint8
const (
StatusWaiting = 1 // 等待下注中
StatusChoosing = 2 // 计算中
StatusShowing = 3 // 显示结果中
)
package game_e
type GameType uint32
var GameLudoDiamondList = []uint32{0, 100, 500, 1000, 5000, 10000}
const (
GameTypeLudo GameType = 1 // ludo
GameTypeUno GameType = 2 // uno
)
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
import "git.hilo.cn/hilo-common/resource/mysql"
//国家势力状态
type GroupPowerStatus = mysql.Type
const (
//上架
GroupPowerUserHas GroupPowerStatus = 1
//未上架
GroupPowerUserNo GroupPowerStatus = 2
//解散
GroupPowerDissolve GroupPowerStatus = 3
)
//国家势力用户角色
type GroupPowerUserRole = mysql.Type
const (
//普通用户
GroupPowerUserRoleUser GroupPowerUserRole = 1
//势力主
GroupPowerUserRoleMgr GroupPowerUserRole = 2
)
//国家势力日志操作类型
type GroupPowerUserLogType = mysql.Type
const (
//加入
GroupPowerUserLogTypeUserJoin GroupPowerUserLogType = 1
//用户自己离开
GroupPowerUserLogTypeUserLeave GroupPowerUserLogType = 2
//运营平台赋予管理者
GroupPowerUserLogTypeOwerJoin GroupPowerUserLogType = 3
//管理人让用户离开
GroupPowerUserLogTypeMgrLeave GroupPowerUserLogType = 4
//管理人解散
GroupPowerUserLogDissolve GroupPowerUserLogType = 5
)
type GroupPowerDiamondLogType = mysql.Type
const (
//群组原因加入
GroupPowerDiamondLogTypeByGroup GroupPowerDiamondLogType = 1
//群主原因加入
GroupPowerDiamondLogTypeByGroupOwer GroupPowerDiamondLogType = 2
)
type PowerSupportAwardState = uint
const (
PowerSuppportNo PowerSupportAwardState = 0 // 未达到要求
PowerSuppportAwarded PowerSupportAwardState = 1 // 已经领取
PowerSuppportWaiting PowerSupportAwardState = 2 // 待领取
)
package group_e
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
const (
GroupEditProfileSignal TypeSignalMsg = 1
GroupRoleChangeSignal TypeSignalMsg = 2
GroupMicChangeSignal TypeSignalMsg = 3 //保留
GroupMsgBannedSignal TypeSignalMsg = 4
GroupMemberRemoveSignal TypeSignalMsg = 5
GroupGiftSignal TypeSignalMsg = 6 //礼物
GroupMicInSignal TypeSignalMsg = 7
GroupMicOutSignal TypeSignalMsg = 8
GroupMicLockSignal TypeSignalMsg = 9
GroupMicUnLockSignal TypeSignalMsg = 10
GroupMicSpeechOpenSignal TypeSignalMsg = 11
GroupMicSpeechCloseSignal TypeSignalMsg = 12
GroupKickOut TypeSignalMsg = 13 //保留
GroupSocketMicOutSignal TypeSignalMsg = 14 //保留
GroupInviteMicInSignal TypeSignalMsg = 15 //邀请上麦保留
GroupInSignal TypeSignalMsg = 16 //进入房间,进房特效
GroupMicEmoji TypeSignalMsg = 17 //麦上表情
GroupLuckyWheel TypeSignalMsg = 18 //转盘的通知信令
GroupOutSignal TypeSignalMsg = 19 //离开房间
GroupRocketState TypeSignalMsg = 20 //火箭状态变化
GroupOnlineUser TypeSignalMsg = 21 //房间在线用户信息
GroupMicChange TypeSignalMsg = 22 //房间麦位上的变量
GroupMemberInvite TypeSignalMsg = 23 //房间-邀请用户成为会员
GroupRoleChange TypeSignalMsg = 24 //房间-用户群组身份变化
GroupClearScreen TypeSignalMsg = 25 //房间-清理公屏
)
//群组麦位数量类型
type GroupMicNumType = mysql.Type
const (
OneMicNumType GroupMicNumType = 5
TwoMicNumType GroupMicNumType = 10
ThreeMicNumType GroupMicNumType = 3
FourMicNumType GroupMicNumType = 4
SixMicNumType GroupMicNumType = 6
SevenMicNumType GroupMicNumType = 7
EightMicNumType GroupMicNumType = 8
NineMicNumType GroupMicNumType = 9
ElevenMicNumType GroupMicNumType = 11
TwelveMicNumType GroupMicNumType = 12
ThirteenMicNumType GroupMicNumType = 13
FourteenMicNumType GroupMicNumType = 14
FifteenMicNumType GroupMicNumType = 15
SixteenMicNumType GroupMicNumType = 16
SeventeenMicNumType GroupMicNumType = 17
EighteenMicNumType GroupMicNumType = 18
NineteenMicNumType GroupMicNumType = 19
TwentyMicNumType GroupMicNumType = 20
//5个麦位
FiveMicNumType GroupMicNumType = 1
//10个麦位
TenMicNumType GroupMicNumType = 2
//
SUPPORT_LEVEL_BOUNDARY_HOUR = 0
SUPPORT_LEVEL_PERIOD_DAY = 7
)
type GroupRoleType = uint16
const (
// 群组角色
GROUP_VISITOR GroupRoleType = 0 // 游客
GROUP_MEMBER GroupRoleType = 1 // 成员
GROUP_ADMIN GroupRoleType = 10 // 管理员
GROUP_MANAGER GroupRoleType = 50 // 经理
GROUP_OWNER GroupRoleType = 100 // owner
)
// 群组内游戏相关
const (
GROUP_DICE_NUM_DEFAULT = 5
GROUP_DICE_NUM_MAX = 5
)
const DefaultMsgParallelSize = 20
const (
CREATE_GROUP_MAX_ATTEMPT = 10
NewGroupNamePrefix = "HTGS#"
OverseaGroupNamePrefix = NewGroupNamePrefix + "a"
)
var GROUP_RECOMMEND_SIZE = 5
var GROUP_CREATE_LIMIT = 1
var GROUP_DEFAULT_CODE_LENGTH uint16 = 8
const (
// 上下架状态
SWITCH_ON = 1
SWITH_OFF = 0
)
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 luckyWheel_e
const LUCKY_WHEEL_SEAT_NUM = 10 // 轮盘座位数
const LUCKY_WHEEL_ROLL_TIME = 8 // 轮盘淘汰一个人需要的时间(秒)
const LUCKY_WHEEL_LAST_ROLL_TIME = 5 // 最后一轮出胜利者需要的时间(秒)
const LUCKY_WHEEL_SHOW_TIMELONG = 5 // 轮盘结束后真空期
const LUCKY_WHEEL_WINNER_PERCENTILE = 90 // 赢家分成比例
const LUCKY_WHEEL_OWNER_PERCENTILE = 5 // 群主分成比例
type LuckyWheelStatusType = uint8
const (
NONE LuckyWheelStatusType = 0 // 没有活动/已结束
CREATED LuckyWheelStatusType = 1 // 创建,等待用户加入
ROLLING LuckyWheelStatusType = 2 // 转动中
SHOWING LuckyWheelStatusType = 3 // 结果展示中
RESTARTING LuckyWheelStatusType = 4 // 重启中
)
type LuckyWheelEndStatusType = uint8
const (
DONE LuckyWheelEndStatusType = 0 // 正常结束
USER_CANCELED LuckyWheelEndStatusType = 1 // 用户取消
TIME_OUT_CANCELED LuckyWheelEndStatusType = 2 // 超时未开始结束
)
package luckybox_e
import "git.hilo.cn/hilo-common/resource/mysql"
type AwardTypeLuckyboxAward = mysql.Type
const (
Diamond AwardTypeLuckyboxAward = 1
)
type StatusLuckyboxCycleUser = mysql.Type
const (
NoReceive StatusLuckyboxCycleUser = 1
HasReceive StatusLuckyboxCycleUser = 2
)
package match_e
import "git.hilo.cn/hilo-common/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
type MsgIdType = uint
const (
MSG_ID_GROUP_NAME MsgIdType = 101
MSG_ID_GROUP_INTRODUCTION MsgIdType = 102
MSG_ID_GROUP_NOTIFICATION MsgIdType = 103
MSG_ID_GROUP_WELCOME MsgIdType = 104
MSG_ID_GROUP_INVITE MsgIdType = 105
MSG_ID_GROUP_LEAVE_POWER MsgIdType = 106
MSG_ID_ALL_GROUP_ROCKET MsgIdType = 107
MSG_ID_ROOM_MEADAL MsgIdType = 108
MSG_ID_VIDEO_PUSH_TITITLE MsgIdType = 109
MSG_ID_VIDEO_PUSH_CONTENT MsgIdType = 110
MSG_ID_REPEAT_ACCOUNT MsgIdType = 111
MSG_ID_USER_TRANSFER MsgIdType = 114
MSG_ID_NO_POWER_TO_SVIP6 MsgIdType = 115 // 不能对svip6做某些动作
)
package online_e
type OnlineStatusType = uint
// 在线状态
const (
IM_STATUS_OFF_LINE OnlineStatusType = 0
IM_STATUS_PUSH_ON_LINE OnlineStatusType = 1
IM_STATUS_ON_LINE OnlineStatusType = 2
)
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
)
...@@ -51,3 +51,45 @@ const ( ...@@ -51,3 +51,45 @@ const (
//公有,自己获取 //公有,自己获取
Public ResMedalScope = 2 Public ResMedalScope = 2
) )
type ResPropertyAvatarType = mysql.Type
const (
SendGiftCpPropertyAvatarType ResPropertyAvatarType = 1 //周CP
MonthlyWealthPropertyAvatarType ResPropertyAvatarType = 2 //月冠财富榜
MonthlyCharmPropertyAvatarType ResPropertyAvatarType = 3 //月冠魅力榜
MonthlyPayPropertyAvatarType ResPropertyAvatarType = 4 //月冠充值榜
)
type ResMedalObtainType = mysql.Type
const (
WealthResMedalObtainType ResMedalObtainType = 1
CharmResMedalObtainType ResMedalObtainType = 2
GiftResMedalObtainType ResMedalObtainType = 3
BoomRocketResMedalObtainType ResMedalObtainType = 4
ActityResMedalObtainType ResMedalObtainType = 5
FruitKingResMedalObtainType ResMedalObtainType = 6
LuckyBoxKingResMedalObtainType ResMedalObtainType = 7
VideoChatResMedalObtainType ResMedalObtainType = 8
)
type ResGroupSupportGrade = mysql.Type
const (
Agrade ResGroupSupportGrade = 1
Bgrade ResGroupSupportGrade = 2
Cgrade ResGroupSupportGrade = 3
Dgrade ResGroupSupportGrade = 4
Egrade ResGroupSupportGrade = 5
Fgrade ResGroupSupportGrade = 6
Ggrade ResGroupSupportGrade = 7
Hgrade ResGroupSupportGrade = 8
Igrade ResGroupSupportGrade = 9
Jgrade ResGroupSupportGrade = 10
Kgrade ResGroupSupportGrade = 11
Lgrade ResGroupSupportGrade = 12
Mgrade ResGroupSupportGrade = 13
Ngrade ResGroupSupportGrade = 14
Ograde ResGroupSupportGrade = 15
)
package user_e
import "git.hilo.cn/hilo-common/resource/mysql"
type CountType mysql.Type
const (
//我喜欢的数量
CountTypeLike CountType = 1
//我拉黑的数量
CountTypeBlock CountType = 2
//我被喜欢的次数
CountTypeLikeMe CountType = 3
)
package user_e
var HEART_VALUE_MAX uint32 = 2000
...@@ -39,3 +39,26 @@ const ( ...@@ -39,3 +39,26 @@ const (
AwardTypeNoble AwardType = 4 // 贵族 AwardTypeNoble AwardType = 4 // 贵族
AwardTypeRide AwardType = 5 // 座驾 AwardTypeRide AwardType = 5 // 座驾
) )
const (
//购买
UserVipTypeBuy UserVipType = 1
//赠送
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
)
package group_k
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/redis_key"
)
const (
GroupPrefix = "group:"
GroupLock = GroupPrefix + "lock:${user_id}"
GroupSupportAwardIp = GroupPrefix + "support:award:ip:${ip}" // string, ttl=7天-n ip领取扶持次数
EditGroupCd = "edit:group:cd:${imGroupId}"
GroupInfo = "group:info:%s"
)
// 创建群组并发锁
func GetGroupLockKey(userId mysql.ID) string {
return redis_key.ReplaceKey(GroupLock, fmt.Sprintf("%d", userId))
}
// ip领取扶持次数
func GetGroupSupportAwardIpKey(ip mysql.Str) string {
return redis_key.ReplaceKey(GroupSupportAwardIp, ip)
}
// 编辑群组资料cd
func GetEditGroupCDKey(imGroupId mysql.Str) string {
return redis_key.ReplaceKey(EditGroupCd, imGroupId)
}
//
func GetGroupInfoKey(imGroupId mysql.Str) string {
return fmt.Sprintf(GroupInfo, imGroupId)
}
package redis_key package redis_key
import ( import (
"fmt"
"os" "os"
) )
...@@ -22,4 +23,10 @@ func ReplaceKey(keyFmt string, arg ...string) string { ...@@ -22,4 +23,10 @@ func ReplaceKey(keyFmt string, arg ...string) string {
i++ i++
return return
}) })
} }
\ No newline at end of file
const UserMedalMerge = "user:medalMerge:%d" // 勋章
func GetUserMedalMerge(userId uint64) string {
return fmt.Sprintf(UserMedalMerge, userId)
}
package redis_key
import (
"strconv"
"strings"
"time"
)
//online
const online = "online"
//online
const onlineVersion = "online_{version}"
//online lock
const onlineLock = "online_lock_{version}"
//redis的广播,接收到的数据,匹配结果锁
const matchCycleSuccessSubscribeLock = "match_cycle_success_subscribe_lock_{matchUid}"
//redis的广播,接收到的数据,匹配周期结果锁
const matchCycleSubscribeLock = "match_cycle_subscribe_lock_{version}"
//redis的广播,match数据的进行
const matchCron = "match_cron_{dateStr}"
//匹配的工会用户
const matchTradeUnion = "match_trade_union_{version}"
//匹配,用户信息
const matchUser = "match_user_{version}"
//匹配,用户优先度排序
const matchPriority = "match_priority_{version}"
//匹配,质量分数
const matchExcellent = "match_excellent_{version}"
//匹配,关系分数
const matchRelation = "match_relation_{version}_{userId}"
//匹配优先度构成
const matchPriorityForm = "match_priority_form_{version}"
//匹配,质量分数构成
const matchExcellentForm = "match_excellent_form_{version}"
//匹配,关系分数构成
const matchRelationForm = "match_relation_form_{version}"
//匹配,拉黑名单
const matchBlock = "match_block_{version}"
//匹配,条件性别
const matchConditionSex = "match_condition_sex_{version}"
//匹配,条件国家
const matchConditionCountry = "match_condition_country_{version}"
//匹配确认
const matchConfirm = "match_confirm_{channelId}"
//匹配免费确认
const matchAddFreeTime = "match_add_free_time_{matchUid}"
//匹配第一帧
const matchCallReady = "match_call_ready_{matchUid}"
//已匹配的周期
const matchCycle = "match_cycle_{cycle}"
//用户召回弹窗
const recallWindow = "match_recall_window_{userId}"
//用户匹配拒绝的时间, 24小时过期
const userBeMatchRefuse = "user_be_match_refuse_{userId}"
//用户匹配确认的时间
const userValidMatchConfirm = "user_valid_match_confirm_{userId}"
//用户活跃时间
const userActiveTime = "user_active_time"
//推荐用户活跃时间
const recommendActiveTime = "recommend_active_time"
//每一分钟的产生的推荐列表,存在有效期,有效期是一天
const recommentListUnix = "recomment_list_{unix}"
//每一分钟的产生的推荐列表,加锁,避免多次产生
const recommentListUnixLock = "recomment_list_{unix}_lock"
//推荐用户, 记录起来,用户算法中心获取。
const recommendUser = "recommend_user"
//
//1对1视频第一帧
const videoCallReady = "video_call_ready_{videoUid}"
//1对1视频第免费确认
const videoAddFreeTime = "video_add_free_time_{videoUid}"
// 用户日活
const countDailyUserLoginPreix = "daily_user_login_{date}"
// IM在线状态
const onlineStatusPreix = "online_status_{extId}"
// user状态
const userStatusPrefix = "user_status_{userId}"
// mgr_imei统计数
const mgrImeiCountPrefix = "mgr_imei_count_{imei}"
// mgr_ip统计数
const mgrIpCountPrefix = "mgr_ip_count_{ip}"
// 群成员人数
const groupMemberCountPrefix = "group_mem_count_{groupId}"
// 群的成员
const GroupMemberPrefix = "group_member_{groupId}"
// 群消费额
const GroupConsumePrefix = "group_consume_{groupId}"
//榜单活动开始锁
const activityBillboardMatchBeLikeStartLock = "activity_billboard_matchBeLike_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMatchBeLikeEndLock = "activity_billboard_matchBeLike_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardMatchBeLikeRewardLock = "activity_billboard_matchBeLike_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardCpStartLock = "activity_billboard_cp_start_lock_{date}"
//榜单活动结束锁
const activityBillboardCpEndLock = "activity_billboard_cp_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardCpRewardLock = "activity_billboard_cp_reward_lock_{date}"
//榜单活动开始锁
const activityGroupBillboardStartLock = "activity_group_billboard_start_lock_{date}"
//榜单活动开始锁
const activityGroupBillboardEndLock = "activity_group_billboard_end_lock_{date}"
//榜单活动发布奖励锁
const activityGroupBillboardRewardLock = "activity_group_billboard_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardMonthlyWealthStartLock = "activity_billboard_monthly_wealth_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMonthlyWealthEndLock = "activity_billboard_monthly_wealth_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardMonthlyWealthRewardLock = "activity_billboard_monthly_wealth_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardMonthlyCharmStartLock = "activity_billboard_monthly_charm_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMonthlyCharmEndLock = "activity_billboard_monthly_charm_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardMonthlyCharmRewardLock = "activity_billboard_monthly_charm_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardMonthlyPayStartLock = "activity_billboard_monthly_pay_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMonthlyPayEndLock = "activity_billboard_monthly_pay_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardMonthlyPayRewardLock = "activity_billboard_monthly_pay_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardMonthlyGroupStartLock = "activity_billboard_monthly_group_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMonthlyGroupEndLock = "activity_billboard_monthly_group_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardMonthlyGroupRewardLock = "activity_billboard_monthly_group_reward_lock_{date}"
//榜单活动结束锁
const activityBillboardTunisiaMationalDayUserEndLock = "activity_billboard_tunisia_mational_day_user_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardTunisiaMationalDayUserRewardLock = "activity_billboard_tunisia_mational_day_user_reward_lock_{date}"
//榜单活动结束锁
const activityBillboardTunisiaMationalDayGroupEndLock = "activity_billboard_tunisia_mational_day_group_end_lock_{date}"
//榜单活动奖励锁
const activityBillboardTunisiaMationalDayGroupRewardLock = "activity_billboard_tunisia_mational_day_group_reward_lock_{date}"
//榜单活动开始锁
const activityBillboardDayPayDealerStartLock = "activity_billboard_day_pay_dealer_start_lock_{date}"
//榜单活动结束锁
const activityBillboardDayPayDealerEndLock = "activity_billboard_day_pay_dealer_end_lock_{date}"
//榜单活动开始锁
const activityBillboardMonthPayDealerStartLock = "activity_billboard_month_pay_dealer_start_lock_{date}"
//榜单活动结束锁
const activityBillboardMonthPayDealerEndLock = "activity_billboard_month_pay_dealer_end_lock_{date}"
//周星PK活动
const activityBillboardGroupStartPk = "activity_billboard_group_start_pk_lock_{date}"
//活动周期
const activityCronNewLock = "activity_cron_new_lock_{type}_{timestamp}"
const activityCronEndLock = "activity_cron_end_lock_{type}_{timestamp}"
const activityCronRewardLock = "activity_cron_reward_lock_{type}_{timestamp}"
// 礼物周星活动互斥锁
const weeklyStarStartLock = "weekly_star_start_lock_{date}"
const weeklyStarEndLock = "weekly_star_end_lock_{date}"
const weeklyStarRewardLock = "weekly_star_reward_lock_{date}"
// 国家之星cron互斥锁
const countryStarCronLock = "country_star_cron_{task}_{date}"
//群的最大消息序列号
const groupMsgSeqMaxAll = "group_msg_seq_max_all"
//群中用户的最大消息序列号
const groupMsgSeqMaxGroup = "group_msg_seq_max_{uuid}"
//5分钟内群中消息用户数量(所有群)
const groupMsgDurationUser = "group_msg_duration_user"
//5分钟内群中消息用户数的群排名
const groupMsgDurationScore = "group_msg_duration_score"
//快照
const groupMsgDurationScoreSnap = "group_msg_duration_score_snap"
// 15天内进入房间的人(重复进入去重)
const groupInUserDuration = "group_in_user_duration_{groupUuid}"
// 15天内进入房间的人数
const roomVisitCount = "room_visit_count"
// 用户进入过的房间及时间
const userEnterRoom = "enter_room_{userId}"
// 群支持度
const supportLevel = "supportLevel_{date}"
// 国家势力周期内收获的钻石
const groupPowerDiamond = "group_diamond_{period}"
// 国家Icon
const countryIcon = "contry_icon"
// 群贡献前三
const groupTop3Consume = "group_top3_consume_{period}_{groupId}"
// 国家贡献前三
const countryTop3Consume = "country_top3_consume_{country}"
//群组麦位内容
const groupMicGroup = "group_mic_{groupUuid}"
//核心
//群组麦上的人
const groupMicUser = "group_mic_user_{groupUuid}_{i}"
//核心
//麦上的人,用于控制一个只能上一个麦,利用lua表达式,让groupUserMic 同 groupMicUser保持一致性。
const groupUserInMic = "group_user_in_mic_{externalId}"
//群组麦上del锁
const groupMicUserDelLock = "group_mic_user_del_lock_{groupUuid}_{i}"
//群组麦上上麦锁
const groupMicUserInLock = "group_mic_user_in_lock_{userId}"
//群组踢人,设计有效期,有效期一过,踢人时效性就没有了。
const groupKickGroupUuidUserId = "group_kick_{groupUuid}_{userId}"
//群发言, 记录在哪个群发过言,
const groupMsgDateUser = "group_msg_{date}_{userExternalId}"
//群麦上数量类型设置
const groupMicNumType = "group_mic_num_type_{groupUuid}"
//麦上有人的群
const groupMicHasIn = "group_mic_has_in"
//麦上有人的群+用户+时间
const groupMicHasInUserTime = "group_mic_has_in_user_time"
//在房间的人
const groupRoomLiving = "group_room_living"
//定时任务锁,系统消息锁
const msgSysCronLock = "msg_sys_cron_lock"
//一周下群组消息的人, set结构
const groupMsgWeekUser = "group_msg_week_user_{groupId}"
//一周下群组消息的人数(是人数), sort set结构
const groupMsgWeekUserN = "group_msg_week_user_n"
//每天领取的钻石
const dailyInAppDiamond = "daily_in_app_diamond"
//定时任务,vip订阅检查
const vipSubscribeLock = "vip_subscribe_lock"
const giftReturnLock = "gift_return_lock"
// 定时任务的互斥锁
const cronLock = "cronLock:{subKey}"
const authorizeWindow = "authorize_window_{userId}"
const syncTimHiloLock = "sync_tim_hilo_{userId}"
// 火箭观众
const rocketGuest = "rocket_guest_{id}_{userId}"
// 用户访问运营弹窗
const operationWindow = "operation_window_{date}_{userId}"
//上麦10分钟.设计:双重保证,存在过期时间,判断key中带有时间
const taskMic10Min = "task_mic_10_min_{userId}_{dateStr}"
//活跃值,(每3分钟,就有1分),设计:3分钟过期,存在,则说明还不到三分钟。
const actityDailyInMic = "actity_daily_in_mic_{userId}"
//幸运盒子购买钻石-奖励钻石的结果差值。存在有效期
const luckyboxBuyAward = "luckybox_buy_award_{userId}"
// 用户请求频率
const userQps = "user_qps_{userId}_{sec}"
// 用户URL请求频率
const userUrlQps = "user_qps_{userId}_{url}_{sec}"
//国家势力流水,按周
const groupPowerDiamondLogWeek = "group_power_diamond_log_week_{dateStr}"
//sortset 结构 key:date key:groupUid score:得分
const giftOperateDay = "gift_operate_groupUid_day_{dateStr}"
const giftOperateWeek = "gift_operate_groupUid_week_{weekStr}"
const giftOperateMonth = "gift_operate_groupUid_month_{monthStr}"
//sortset 结构 key:date key:senderUserId score:得分
const giftOperateSendUserIdDay = "gift_operate_send_userId_day_{dateStr}"
const giftOperateSendUserIdWeek = "gift_operate_send_userId_week_{weekStr}"
const giftOperateSendUserIdMonth = "gift_operate_send_userId_month_{monthStr}"
//sortset 结构 key:date key:receiveUserId score:得分
const giftOperateReceiveUserIdDay = "gift_operate_receive_userId_day_{dateStr}"
const giftOperateReceiveUserIdWeek = "gift_operate_receive_userId_week_{weekStr}"
const giftOperateReceiveUserIdMonth = "gift_operate_receive_userId_month_{monthStr}"
const giftOperate1HourDurationGroupId = "gift_operate_1hour_duration_groupId_{groupUid}"
//sortset 结构 key:groupUid_date key:userId score:得分
const giftOperateGroupUidDay = "gift_operate_groupUid_day_{dateStr}_{groupUid}"
const giftOperateGroupUidWeek = "gift_operate_groupUid_week_{dateStr}_{groupUid}"
const giftOperateGroupUidMonth = "gift_operate_groupUid_month_{monthStr}_{groupUid}"
const giftOperateReceiveGroupUidDay = "gift_operate_receive_groupUid_day_{dateStr}_{groupUid}"
const giftOperateReceiveGroupUidWeek = "gift_operate_receive_groupUid_week_{dateStr}_{groupUid}"
const giftOperateReceiveGroupUidMonth = "gift_operate_receive_groupUid_month_{monthStr}_{groupUid}"
//幸运盒子的活动,记录用户的中奖总额
const luckyboxUserSumSunday = "luckyboxUserSum_{sunday}"
//幸运盒子的活动,记录奖金池的数量
const luckyboxPoolSumSunday = "luckyboxPoolSum_{sunday}"
const groupOnlineUser = "group_online_user_{groupUid}"
const micInfoChange = "mic_info_change"
const micInUserTemp = "mic_in_user_temp_{userExternalIds}"
//视频分钟,定时状态check,检查
const videoMinuteCronCheck = "video_minute_cron_check_{uuid}"
const videoMinuteCronDeal = "video_minute_cron_deal_{uuid}"
const videoMinuteCronEnd = "video_minute_cron_end_{videoUid}"
//下一个扣钱的队列, 使用sort set结构,
//const videoNextMinute = "video_next_minute"
// --------------------------缓存时间相关常量-------------------------------------------
const GroupInDurationTTL = 15
const GroupInDurationClearPeriod = 15
func GetPrefixOnline() string {
return online
}
func GetPrefixOnlineVersion(version string) string {
return strings.Replace(onlineVersion, "{version}", version, -1)
}
func GetPrefixOnlineLock(version string) string {
return strings.Replace(onlineLock, "{version}", version, -1)
}
func GetPrefixMatchUser(version string) string {
return strings.Replace(matchUser, "{version}", version, -1)
}
func GetPrefixMatchPriority(version string) string {
return strings.Replace(matchPriority, "{version}", version, -1)
}
func GetPrefixMatchExcellent(version string) string {
return strings.Replace(matchExcellent, "{version}", version, -1)
}
func GetPrefixMatchRelation(version string, userId string) string {
return strings.Replace(strings.Replace(matchRelation, "{version}", version, -1), "{userId}", userId, -1)
}
func GetPrefixMatchPriorityForm(version string) string {
return strings.Replace(matchPriorityForm, "{version}", version, -1)
}
func GetPrefixMatchExcellentForm(version string) string {
return strings.Replace(matchExcellentForm, "{version}", version, -1)
}
func GetPrefixMatchRelationForm(version string) string {
return strings.Replace(matchRelationForm, "{version}", version, -1)
}
func GetPrefixMatchBlock(version string) string {
return strings.Replace(matchBlock, "{version}", version, -1)
}
func GetPrefixMatchConditionSex(version string) string {
return strings.Replace(matchConditionSex, "{version}", version, -1)
}
func GetPrefixMatchConditionCountry(version string) string {
return strings.Replace(matchConditionCountry, "{version}", version, -1)
}
func GetPrefixMatchConfirm(channelId string) string {
return strings.Replace(matchConfirm, "{channelId}", channelId, -1)
}
func GetPrefixMatchAddFreeTime(matchUid string) string {
return strings.Replace(matchAddFreeTime, "{matchUid}", matchUid, -1)
}
func GetPrefixMatchCallReady(matchUid string) string {
return strings.Replace(matchCallReady, "{matchUid}", matchUid, -1)
}
func GetPrefixMatchCycle(cycle int64) string {
return strings.Replace(matchCallReady, "{matchUid}", strconv.Itoa(int(cycle)), -1)
}
func GetPreMatchTradeUnion(version string) string {
return strings.Replace(matchTradeUnion, "{version}", version, -1)
}
func GetPreMatchCycleSuccessSubscribeLock(matchUid string) string {
return strings.Replace(matchCycleSuccessSubscribeLock, "{matchUid}", matchUid, -1)
}
func GetPreMatchCycleSubscribeLock(version string) string {
return strings.Replace(matchCycleSubscribeLock, "{version}", version, -1)
}
func GetPreMatchCron(dateStr string) string {
return strings.Replace(matchCron, "{dateStr}", dateStr, -1)
}
func GetPreRecallWindow(userId uint64) string {
return strings.Replace(recallWindow, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPreUserBeMatchRefuse(userId uint64) string {
return strings.Replace(userBeMatchRefuse, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPreUserValidMatchConfirm(userId uint64) string {
return strings.Replace(userValidMatchConfirm, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPreUserActiveTime() string {
return userActiveTime
}
func GetPreRecommendActiveTime() string {
return recommendActiveTime
}
func GetPreRecommendUser() string {
return recommendUser
}
func GetPreRecommentListUnix(unix string) string {
return strings.Replace(recommentListUnix, "{unix}", unix, -1)
}
func GetPreRecommentListUnixLock(unix string) string {
return strings.Replace(recommentListUnixLock, "{unix}", unix, -1)
}
func GetPrefixVideoCallReady(videoUid string) string {
return strings.Replace(videoCallReady, "{videoUid}", videoUid, -1)
}
func GetPrefixVideoAddFreeTime(videoUid string) string {
return strings.Replace(videoAddFreeTime, "{videoUid}", videoUid, -1)
}
func GetPrefixActivityBillboardMatchBeLikeStartLock(date string) string {
return strings.Replace(activityBillboardMatchBeLikeStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMatchBeLikeEndLock(date string) string {
return strings.Replace(activityBillboardMatchBeLikeEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMatchBeLikeRewardLock(date string) string {
return strings.Replace(activityBillboardMatchBeLikeRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardCpStartLock(date string) string {
return strings.Replace(activityBillboardCpStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardCpEndLock(date string) string {
return strings.Replace(activityBillboardCpEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardCpRewardLock(date string) string {
return strings.Replace(activityBillboardCpRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyWealthStartLock(date string) string {
return strings.Replace(activityBillboardMonthlyWealthStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyWealthEndLock(date string) string {
return strings.Replace(activityBillboardMonthlyWealthEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyWealthRewardLock(date string) string {
return strings.Replace(activityBillboardMonthlyWealthRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyCharmStartLock(date string) string {
return strings.Replace(activityBillboardMonthlyCharmStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyCharmEndLock(date string) string {
return strings.Replace(activityBillboardMonthlyCharmEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyCharmRewardLock(date string) string {
return strings.Replace(activityBillboardMonthlyCharmRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyPayStartLock(date string) string {
return strings.Replace(activityBillboardMonthlyPayStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyPayEndLock(date string) string {
return strings.Replace(activityBillboardMonthlyPayEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyPayRewardLock(date string) string {
return strings.Replace(activityBillboardMonthlyPayRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyGroupStartLock(date string) string {
return strings.Replace(activityBillboardMonthlyGroupStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyGroupEndLock(date string) string {
return strings.Replace(activityBillboardMonthlyGroupEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthlyGroupRewardLock(date string) string {
return strings.Replace(activityBillboardMonthlyGroupRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardTunisiaMationalDayUserEndLock(date string) string {
return strings.Replace(activityBillboardTunisiaMationalDayUserEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardTunisiaMationalDayUserRewardLock(date string) string {
return strings.Replace(activityBillboardTunisiaMationalDayUserRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardTunisiaMationalDayGroupEndLock(date string) string {
return strings.Replace(activityBillboardTunisiaMationalDayGroupEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardTunisiaMationalDayGroupRewardLock(date string) string {
return strings.Replace(activityBillboardTunisiaMationalDayGroupRewardLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardDayPayDealerStartLock(date string) string {
return strings.Replace(activityBillboardDayPayDealerStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardDayPayDealerEndLock(date string) string {
return strings.Replace(activityBillboardDayPayDealerEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthPayDealerStartLock(date string) string {
return strings.Replace(activityBillboardMonthPayDealerStartLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardMonthPayDealerEndLock(date string) string {
return strings.Replace(activityBillboardMonthPayDealerEndLock, "{date}", date, -1)
}
func GetPrefixActivityBillboardGroupStartPkLock(date string) string {
return strings.Replace(activityBillboardGroupStartPk, "{date}", date, -1)
}
//活动周期
//const activityCronEndLock = "activity_cron_end_lock_{type}_{timestamp}"
//const activityCronRewardLock = "activity_cron_reward_lock_{type}_{timestamp}"
func GetPrefixActivityCronNewLock(t uint8, ti time.Time) string {
return strings.Replace(strings.Replace(activityCronNewLock, "{type}", strconv.FormatUint(uint64(t), 10), -1), "{timestamp}", strconv.FormatInt(ti.Unix(), 10), -1)
}
func GetPrefixActivityCronEndLock(t uint8, ti time.Time) string {
return strings.Replace(strings.Replace(activityCronEndLock, "{type}", strconv.FormatUint(uint64(t), 10), -1), "{timestamp}", strconv.FormatInt(ti.Unix(), 10), -1)
}
func GetPrefixActivityCronRewardLock(t uint8, ti time.Time) string {
return strings.Replace(strings.Replace(activityCronRewardLock, "{type}", strconv.FormatUint(uint64(t), 10), -1), "{timestamp}", strconv.FormatInt(ti.Unix(), 10), -1)
}
func GetWeeklyStarStartLockKey(date string) string {
return strings.Replace(weeklyStarStartLock, "{date}", date, -1)
}
func GetWeeklyStarEndLockKey(date string) string {
return strings.Replace(weeklyStarEndLock, "{date}", date, -1)
}
func GetWeeklyStarRewardLockKey(date string) string {
return strings.Replace(weeklyStarRewardLock, "{date}", date, -1)
}
func GetCountryStarCronLock(task, date string) string {
return strings.Replace(strings.Replace(countryStarCronLock, "{task}", task, -1), "{date}", date, -1)
}
func GetPrefixActivityGroupBillboardStartLock(date string) string {
return strings.Replace(activityGroupBillboardStartLock, "{date}", date, -1)
}
func GetPrefixActivityGroupBillboardEndLock(date string) string {
return strings.Replace(activityGroupBillboardEndLock, "{date}", date, -1)
}
func GetPrefixActivityGroupBillboardRewardLock(date string) string {
return strings.Replace(activityGroupBillboardRewardLock, "{date}", date, -1)
}
func GetPrefixGroupMsgSeqMaxAll() string {
return groupMsgSeqMaxAll
}
func GetPrefixGroupMsgSeqMaxGroup(groupUuid string) string {
return strings.Replace(groupMsgSeqMaxGroup, "{uuid}", groupUuid, -1)
}
func GetPrefixGroupMsgDurationUser() string {
return groupMsgDurationUser
}
func GetPrefixGroupMsgDurationScore() string {
return groupMsgDurationScore
}
func GetPrefixGroupMsgDurationScoreSnap() string {
return groupMsgDurationScoreSnap
}
func GetPrefixGroupMic(groupUuid string) string {
return strings.Replace(groupMicGroup, "{groupUuid}", groupUuid, -1)
}
func GetPrefixGroupMicUser(groupUuid string, i int) string {
return strings.Replace(strings.Replace(groupMicUser, "{groupUuid}", groupUuid, -1), "{i}", strconv.Itoa(i), -1)
}
func GetPrefixGroupMicUserDelLock(groupUuid string, i int) string {
return strings.Replace(strings.Replace(groupMicUserDelLock, "{groupUuid}", groupUuid, -1), "{i}", strconv.Itoa(i), -1)
}
func GetPrefixGroupMicUserInLock(userId uint64) string {
return strings.Replace(groupMicUserInLock, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPrefixGroupUserInMic(externalId string) string {
return strings.Replace(groupUserInMic, "{externalId}", externalId, -1)
}
func GetGroupKickGroupUuidUserId(groupUuid string, userId uint64) string {
return strings.Replace(strings.Replace(groupKickGroupUuidUserId, "{groupUuid}", groupUuid, -1), "{userId}", strconv.Itoa(int(userId)), -1)
}
func GetGroupMsgDateUser(userExternalId string, date time.Time) string {
return strings.Replace(strings.Replace(groupMsgDateUser, "{date}", date.Format("2006-01-02"), -1), "{userExternalId}", userExternalId, -1)
}
func GetPrefixGroupMsgWeekUser(groupId string) string {
return strings.Replace(groupMsgWeekUser, "{groupId}", groupId, -1)
}
func GetPrefixGroupMsgWeekUserM() string {
return groupMsgWeekUserN
}
func GetMsgSysCronLock() string {
return msgSysCronLock
}
func GetPrefixDailyInAppDiamond() string {
return dailyInAppDiamond
}
func GetPrefixVipSubscribeLock() string {
return vipSubscribeLock
}
func GetGiftReturnLockKey() string {
return giftReturnLock
}
func GetCronLockKey(subKey string) string {
return strings.Replace(cronLock, "{subKey}", subKey, -1)
}
func GetPrefixGroupMicNumType(groupUuid string) string {
return strings.Replace(groupMicNumType, "{groupUuid}", groupUuid, -1)
}
func GetPrefixGroupInUserDuration(groupUuid string) string {
return strings.Replace(groupInUserDuration, "{groupUuid}", groupUuid, -1)
}
func GetUserEnterRoomKey(userId uint64) string {
return strings.Replace(userEnterRoom, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPrefixRoomVisitCount() string {
return roomVisitCount
}
func GetPrefixSupportLevel(date string) string {
return strings.Replace(supportLevel, "{date}", date, -1)
}
func GetPrefixGroupPowerDiamond(period string) string {
return strings.Replace(groupPowerDiamond, "{period}", period, -1)
}
func GetCountryIconKey() string {
return countryIcon
}
func GetGroupTop3ConsumeKey(period string, groupId string) string {
return strings.Replace(strings.Replace(groupTop3Consume, "{period}", period, -1), "groupId", groupId, -1)
}
func GetCountryTop3ConsumeKey(country string) string {
return strings.Replace(countryTop3Consume, "{country}", country, -1)
}
func GetPrefixGroupMicHasIn() string {
return groupMicHasIn
}
func GetPrefixGroupMicHasInUserTime() string {
return groupMicHasInUserTime
}
func GetPrefixAuthorizeWindow(userId uint64) string {
return strings.Replace(authorizeWindow, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetKeySyncTimHilo(userId uint64) string {
return strings.Replace(syncTimHiloLock, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPrefixGroupRoomLiving() string {
return groupRoomLiving
}
func GetOperationWindowKey(date string, userId uint64) string {
return strings.Replace(strings.Replace(operationWindow, "{date}", date, -1), "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPrefixTaskMic10Min(userId uint64, dateStr string) string {
return strings.Replace(strings.Replace(taskMic10Min, "{dateStr}", dateStr, -1), "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetPrefixActityDailyInMic(userId uint64) string {
return strings.Replace(actityDailyInMic, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetCountUserLoginKey(date string) string {
return strings.Replace(countDailyUserLoginPreix, "{date}", date, -1)
}
func GetGroupMemCountKey(groupId string) string {
return strings.Replace(groupMemberCountPrefix, "{groupId}", groupId, -1)
}
func GetOnLineStatusKey(extId string) string {
return strings.Replace(onlineStatusPreix, "{extId}", extId, -1)
}
func GetUserStatusKey(userId uint64) string {
return strings.Replace(userStatusPrefix, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetMgrImeiCountKey(imei string) string {
return strings.Replace(mgrImeiCountPrefix, "{imei}", imei, -1)
}
func GetMgrIpCountKey(ip string) string {
return strings.Replace(mgrIpCountPrefix, "{ip}", ip, -1)
}
func GetRocketGuestKey(resultId uint64, userId uint64) string {
u := strconv.FormatUint(userId, 10)
id := strconv.FormatUint(resultId, 10)
return strings.Replace(strings.Replace(rocketGuest, "{userId}", u, -1), "{id}", id, -1)
}
func GetLuckyboxBuyAward(userId uint64) string {
return strings.Replace(luckyboxBuyAward, "{userId}", strconv.FormatUint(userId, 10), -1)
}
func GetUserQps(userId uint64, sec uint64) string {
return strings.Replace(strings.Replace(userQps, "{userId}", strconv.FormatUint(userId, 10), -1), "{sec}", strconv.FormatUint(sec, 10), -1)
}
func GetUserUrlQps(userId uint64, url string, sec uint64) string {
return strings.Replace(
strings.Replace(
strings.Replace(userUrlQps, "{userId}", strconv.FormatUint(userId, 10), -1),
"{url}", url, -1),
"{sec}", strconv.FormatUint(sec, 10), -1)
}
func GetGroupPowerDiamondLogWeek(dateStr string) string {
return strings.Replace(groupPowerDiamondLogWeek, "{dateStr}", dateStr, -1)
}
func GetGroupOnlineUser(groupUid string) string {
return strings.Replace(groupOnlineUser, "{groupUid}", groupUid, -1)
}
func GetGiftOperateGroupUidDay(groupUid string, dateStr string) string {
return strings.Replace(strings.Replace(giftOperateGroupUidDay, "{groupUid}", groupUid, -1), "{dateStr}", dateStr, -1)
}
func GetGiftOperateGroupUidWeek(groupUid string, dateStr string) string {
return strings.Replace(strings.Replace(giftOperateGroupUidWeek, "{groupUid}", groupUid, -1), "{dateStr}", dateStr, -1)
}
func GetGiftOperateGroupUidMonth(groupUid string, monthStr string) string {
return strings.Replace(strings.Replace(giftOperateGroupUidMonth, "{groupUid}", groupUid, -1), "{monthStr}", monthStr, -1)
}
func GetGiftOperateReceiveGroupUidDay(groupUid string, dateStr string) string {
return strings.Replace(strings.Replace(giftOperateReceiveGroupUidDay, "{groupUid}", groupUid, -1), "{dateStr}", dateStr, -1)
}
func GetGiftOperateReceiveGroupUidWeek(groupUid string, dateStr string) string {
return strings.Replace(strings.Replace(giftOperateReceiveGroupUidWeek, "{groupUid}", groupUid, -1), "{dateStr}", dateStr, -1)
}
func GetGiftOperateReceiveGroupUidMonth(groupUid string, monthStr string) string {
return strings.Replace(strings.Replace(giftOperateReceiveGroupUidMonth, "{groupUid}", groupUid, -1), "{monthStr}", monthStr, -1)
}
func GetGiftOperateDay(dateStr string) string {
return strings.Replace(giftOperateDay, "{dateStr}", dateStr, -1)
}
func GetGiftOperateWeek(weekStr string) string {
return strings.Replace(giftOperateWeek, "{weekStr}", weekStr, -1)
}
func GetGiftOperateMonth(monthStr string) string {
return strings.Replace(giftOperateMonth, "{monthStr}", monthStr, -1)
}
func GetGiftOperateSendUserIdDay(dateStr string) string {
return strings.Replace(giftOperateSendUserIdDay, "{dateStr}", dateStr, -1)
}
func GetGiftOperateSendUserIdWeek(weekStr string) string {
return strings.Replace(giftOperateSendUserIdWeek, "{weekStr}", weekStr, -1)
}
func GetGiftOperateSendUserIdMonth(monthStr string) string {
return strings.Replace(giftOperateSendUserIdMonth, "{monthStr}", monthStr, -1)
}
func GetGiftOperateReceiveUserIdDay(dateStr string) string {
return strings.Replace(giftOperateReceiveUserIdDay, "{dateStr}", dateStr, -1)
}
func GetGiftOperateReceiveUserIdWeek(weekStr string) string {
return strings.Replace(giftOperateReceiveUserIdWeek, "{weekStr}", weekStr, -1)
}
func GetGiftOperateReceiveUserIdMonth(monthStr string) string {
return strings.Replace(giftOperateReceiveUserIdMonth, "{monthStr}", monthStr, -1)
}
func GetGiftOperate1HourDurationGroupId(groupUid string) string {
return strings.Replace(giftOperate1HourDurationGroupId, "{groupUid}", groupUid, -1)
}
func GetLuckyboxUserSum(sunday string) string {
return strings.Replace(luckyboxUserSumSunday, "{sunday}", sunday, -1)
}
func GetLuckyboxPoolSum(sunday string) string {
return strings.Replace(luckyboxPoolSumSunday, "{sunday}", sunday, -1)
}
func GetMicInfoChange() string {
return micInfoChange
}
func GetMicInUserTemp(userExternalIds string) string {
return strings.Replace(micInUserTemp, "{userExternalIds}", userExternalIds, -1)
}
func GetVideoMinuteCronCheck(uuid string) string {
return strings.Replace(videoMinuteCronCheck, "{uuid}", uuid, -1)
}
func GetVideoMinuteCronDeal(uuid string) string {
return strings.Replace(videoMinuteCronDeal, "{uuid}", uuid, -1)
}
func GetVideoMinuteCronEnd(videoUid string) string {
return strings.Replace(videoMinuteCronEnd, "{videoUid}", videoUid, -1)
}
/*func GetVideoNextMinute() string {
return videoNextMinute
}*/
package billboard_cv
import (
"context"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/utils"
"hilo-group/_const/enum/gift_e"
"hilo-group/_const/redis_key"
"hilo-group/cv/gift_cv"
"hilo-group/cv/user_cv"
"sort"
"strconv"
"time"
)
//榜单中用户信息
type BillboardUserInfo struct {
//用户基本信息
UserBase user_cv.CvUserDetail `json:"userBase"`
//数值
Num uint64 `json:"num"`
}
func GetGroupTop3Consume(model *domain.Model, groupId string, myUserId uint64) ([]BillboardUserInfo, error) {
now := time.Now()
period := now.Format(utils.COMPACT_MONTH_FORMAT)
data, err := getGroupTop3Consume(period, groupId)
result := make([]BillboardUserInfo, 0)
failed := false
if err != nil {
failed = true
} else {
model.Log.Infof("GetGroupTop3Consume, from redis: %+v", data)
ts, err := strconv.ParseUint(data["timestamp"], 10, 64)
if err != nil {
failed = true
} else {
// 超过5分钟就认为是过期数据
if now.Unix()-int64(ts) >= 60*5 {
failed = true
}
}
}
if failed {
result, err := BuildMonthlyGroupConsumeBillboard(groupId, 3, myUserId)
if err != nil {
return nil, err
}
diamonds := make(map[uint64]uint64, 0)
for _, i := range result {
if i.UserBase.Id != nil {
diamonds[*i.UserBase.Id] = i.Num
}
}
model.Log.Infof("GetGroupTop3Consume, DB: %+v", diamonds)
ret, err := saveGroupTop3Consume(period, groupId, diamonds)
model.Log.Infof("GetGroupTop3Consume SAVE ret = %d, err: %v", ret, err)
return result, nil
}
userIds := make([]uint64, 0)
diamonds := make(map[uint64]uint64, 0)
for k, v := range data {
if uid, err := strconv.ParseUint(k, 10, 64); err == nil {
if num, err := strconv.ParseInt(v, 10, 64); err == nil {
userIds = append(userIds, uid)
diamonds[uid] = uint64(num)
}
}
}
users, err := user_cv.GetUserDetailMap(userIds, myUserId)
if err != nil {
return nil, err
}
for _, i := range userIds {
if users[i] != nil {
result = append(result, BillboardUserInfo{
UserBase: *users[i],
Num: diamonds[i],
})
}
}
return result, nil
}
func getGroupTop3Consume(period string, groupId string) (map[string]string, error) {
key := redis_key.GetGroupTop3ConsumeKey(period, groupId)
return redisCli.GetRedis().HGetAll(context.Background(), key).Result()
}
func saveGroupTop3Consume(period string, groupId string, diamonds map[uint64]uint64) (int64, error) {
values := make(map[string]interface{}, 0)
for p, d := range diamonds {
if d > 0 {
values[strconv.FormatUint(p, 10)] = d
}
}
if len(values) <= 0 {
return 0, nil
}
values["timestamp"] = time.Now().Unix()
key := redis_key.GetGroupTop3ConsumeKey(period, groupId)
ret, err := redisCli.GetRedis().HSet(context.Background(), key, values).Result()
if err == nil {
// 设置一个TTL保险一些 TODO: 可以优化,保证数据总是有的
redisCli.GetRedis().Expire(context.Background(), key, time.Minute*15)
}
return ret, err
}
func BuildMonthlyGroupConsumeBillboard(groupId string, length int, myUserId uint64) ([]BillboardUserInfo, error) {
//now := time.Now()
//endDate := now.Format(common.DATE_FORMAT)
//beginDate := common.GetFirstDay(now).Format(common.DATE_FORMAT)
return BuildGroupConsumeBillboard(groupId, time.Now(), length, myUserId, "month")
}
func BuildGroupConsumeBillboard(groupId string, endDate time.Time, length int, myUserId uint64, dayWeekMonth string) ([]BillboardUserInfo, error) {
g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType}
scores, err := g.GetGroupConsumeSummary(groupId, endDate, dayWeekMonth)
if err != nil {
return nil, err
}
userIds := make([]uint64, 0)
for k, _ := range scores {
userIds = append(userIds, k)
}
sort.SliceStable(userIds, func(i, j int) bool {
return scores[userIds[i]] > scores[userIds[j]]
})
if length > len(userIds) {
length = len(userIds)
}
userIds = userIds[0:length]
users, err := user_cv.GetUserDetailMap(userIds, myUserId)
if err != nil {
return nil, err
}
result := make([]BillboardUserInfo, 0)
for _, i := range userIds {
if users[i] != nil {
result = append(result, BillboardUserInfo{
UserBase: *users[i],
Num: scores[i],
})
}
}
return result, nil
}
package country_cv
import "hilo-group/_const/enum/country_e"
// cv国家管理人员
type CVCountryManager struct {
Country string `json:"country"` // 国家name
Role country_e.CountryMgrRole `json:"role" swaggertype:"integer"` // 角色 1:国家管理员 2:国家助理
}
package diamond_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
. "git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/diamond_e"
"hilo-group/domain/model/bean_m"
"hilo-group/domain/model/diamond_m"
"hilo-group/myerr"
"strconv"
)
type CvDiamond struct {
//钻石数量
DiamondNum *uint32 `json:"diamondNum"`
//粉钻数量
PinkDiamondNum *uint32 `json:"pinkDiamondNum"`
}
type CvDiamondBean struct {
//钻石数量
DiamondNum uint32 `json:"diamondNum"`
//豆子数量
BeanNum string `json:"beanNum"`
}
func GetDiamondBean(userId mysql.ID) (*CvDiamondBean, error) {
var diamondAccount diamond_m.DiamondAccount
err := mysql.Db.Where(&diamond_m.DiamondAccount{
UserId: userId,
}).First(&diamondAccount).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
diamondAccount = diamond_m.DiamondAccount{
DiamondNum: 0,
}
}
return nil, err
}
var beanAccount bean_m.BeanAccount
err = mysql.Db.Where(&bean_m.BeanAccount{
UserId: userId,
}).First(&beanAccount).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
beanAccount = bean_m.BeanAccount{
BeanNum: 0,
}
}
}
return &CvDiamondBean{DiamondNum: diamondAccount.DiamondNum, BeanNum: strconv.FormatFloat(float64(beanAccount.BeanNum)/100, 'f', 2, 64)}, nil
}
type CvDiamondDetail struct {
//1:增加 2:减少
AddReduce *uint8 `json:"addReduce"`
//6:注册 3:建立融云会话 4:购买钻石 1:发送礼物 5:接受礼物 2:匹配条件
OperateType *uint8 `json:"operateType"`
//钻石的数量
DiamondNum *uint32 `json:"diamondNum"`
//创建时间
CreatedTime *int64 `json:"createdTime"`
}
func GetDiamond(userId mysql.ID) (*CvDiamond, error) {
var diamondAccount diamond_m.DiamondAccount
err := mysql.Db.Where(&diamond_m.DiamondAccount{
UserId: userId,
}).First(&diamondAccount).Error
if err != nil {
return nil, err
}
return &CvDiamond{DiamondNum: NumToUint32(&diamondAccount.DiamondNum), PinkDiamondNum: NumToUint32(&diamondAccount.PinkDiamondNum)}, nil
}
func GetDiamondBalances(userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
result := make(map[mysql.ID]mysql.Num, len(userIds))
data := make([]diamond_m.DiamondAccount, 0)
err := mysql.Db.Where("user_id IN ?", userIds).Find(&data).Error
if err != nil {
return nil, err
}
for _, i := range data {
result[i.UserId] = i.DiamondNum
}
return result, nil
}
//充值记录
func GetDiamondBuyList(userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
var diamondAccountDetails []diamond_m.DiamondAccountDetail
if err := mysql.Db.Model(&diamond_m.DiamondAccountDetail{}).
Where("user_id = ? AND operate_type in (?)", userId, []uint8{diamond_e.BuyDiamond, diamond_e.DealerTransfer, diamond_e.Checkout, diamond_e.PayerMax, diamond_e.Paypal}).
Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
return nil, err
}
var cvDiamondDetails []*CvDiamondDetail
for i := 0; i < len(diamondAccountDetails); i++ {
unixTime := diamondAccountDetails[i].CreatedTime.Unix()
cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
AddReduce: TypeToUint8(&diamondAccountDetails[i].AddReduce),
OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
DiamondNum: NumToUint32(&diamondAccountDetails[i].Num),
CreatedTime: &unixTime,
})
}
return cvDiamondDetails, nil
}
//钻石明细,不包括充值
func GetDiamondDetailList(model *domain.Model, userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
diamondAccountDetails := make([]*diamond_m.DiamondAccountDetail, 0)
offset := (pageIndex - 1) * pageSize
optList := []int{int(diamond_e.BuyDiamond), int(diamond_e.DealerTransfer), int(diamond_e.Checkout), int(diamond_e.PayerMax)}
details := make([]*diamond_m.DiamondAccountDetail, 0)
if offset == 0 { // 首页请求数据,获取 pageSize*3 条过滤返回
sql := "select * from diamond_account_detail where user_id = ? order by id desc limit ?"
if err := mysql.Db.WithContext(model).Raw(sql, userId, pageSize*3).Find(&details).Error; err != nil {
return nil, myerr.WrapErr(err)
}
notInMap := make(map[int]bool)
for _, v := range optList {
notInMap[v] = true
}
for _, v := range details {
if _, ok := notInMap[int(v.OperateType)]; !ok {
diamondAccountDetails = append(diamondAccountDetails, v)
}
}
if len(diamondAccountDetails) > pageSize {
diamondAccountDetails = diamondAccountDetails[:pageSize]
}
}
// 非首页,或者首页没取满 pageSize 条
if offset > 0 || (len(details) == pageSize*3 && len(diamondAccountDetails) < pageSize) {
diamondAccountDetails = make([]*diamond_m.DiamondAccountDetail, 0)
sql := "select * from diamond_account_detail where user_id = ? and operate_type not in (?) order by id desc limit ?,?"
if err := mysql.Db.WithContext(model).Raw(sql, userId, optList, offset, pageSize).
Find(&diamondAccountDetails).Error; err != nil {
return nil, myerr.WrapErr(err)
}
}
//if err := mysql.Db.Table("diamond_account_detail FORCE INDEX(Index_1)").
// Where("user_id = ? AND operate_type not in (?)", userId,
// []int{int(diamond_m2.BuyDiamond), int(diamond_m2.DealerTransfer), int(diamond_m2.Checkout), int(diamond_m2.PayerMax)}).
// Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
// return nil, myerr.WrapErr(err)
//}
cvDiamondDetails := []*CvDiamondDetail{}
for i := 0; i < len(diamondAccountDetails); i++ {
unixTime := diamondAccountDetails[i].CreatedTime.Unix()
cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
AddReduce: TypeToUint8(&diamondAccountDetails[i].AddReduce),
OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
DiamondNum: NumToUint32(&diamondAccountDetails[i].Num),
CreatedTime: &unixTime,
})
}
return cvDiamondDetails, nil
}
//粉钻流水,包含充值
func GetPinkDiamondDetailList(userId mysql.ID, pageSize int, pageIndex int) ([]*CvDiamondDetail, error) {
var diamondAccountDetails []diamond_m.DiamondPinkAccountDetail
if err := mysql.Db.Model(&diamond_m.DiamondPinkAccountDetail{}).
Where("user_id = ?", userId).
Order("id desc").Limit(pageSize).Offset((pageIndex - 1) * pageSize).Find(&diamondAccountDetails).Error; err != nil {
return nil, myerr.WrapErr(err)
}
var cvDiamondDetails []*CvDiamondDetail
for i := 0; i < len(diamondAccountDetails); i++ {
unixTime := diamondAccountDetails[i].CreatedTime.Unix()
cvDiamondDetails = append(cvDiamondDetails, &CvDiamondDetail{
AddReduce: TypeToUint8(&diamondAccountDetails[i].AddReduce),
OperateType: TypeToUint8(&diamondAccountDetails[i].OperateType),
DiamondNum: NumToUint32(&diamondAccountDetails[i].Num),
CreatedTime: &unixTime,
})
}
return cvDiamondDetails, nil
}
package gift_cv
import (
"context"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/utils"
redis2 "github.com/go-redis/redis/v8"
"hilo-group/_const/enum/gift_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/model/gift_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/myerr"
"sort"
"strconv"
"time"
)
type GiftReceive struct {
//礼物名字
Name *string `json:"name"`
//icon地址
IconUrl *string `json:"iconUrl"`
//svag地址
SvagUrl *string `json:"svagUrl"`
//music地址
MusicUrl *string `json:"musicUrl"`
//数量
Num *uint32 `json:"num"`
//总价值
TotolPrice uint32 `json:"totolPrice"`
}
type GiftReceives []*GiftReceive
func (g GiftReceives) Less(i, j int) bool {
return (g[i].TotolPrice) > (g[j].TotolPrice)
}
func (g GiftReceives) Len() int {
return len(g)
}
func (g GiftReceives) Swap(i, j int) {
g[i], g[j] = g[j], g[i]
}
func GetGiftReceive(UserId, reqUserId mysql.ID) ([]*GiftReceive, error) {
if UserId != reqUserId {
// 检查是否svip,是否打开了隐藏礼物墙
// svip信息
svipMap, err := rpc.MGetUserSvip(domain.CreateModelNil(), []uint64{UserId})
if err != nil {
return nil, err
}
if svip, ok := svipMap[UserId]; ok {
for _, v := range svip.Privileges {
if v.Type == 7 && v.CanSwitch && v.UserSwitch {
return nil, nil
}
}
}
}
giftCountUsers := []gift_m.GiftCountUser{}
err := mysql.Db.Model(&gift_m.GiftCountUser{}).Where(&gift_m.GiftCountUser{
UserId: UserId,
}).Find(&giftCountUsers).Error
if err != nil {
return nil, myerr.WrapErr(err)
}
if len(giftCountUsers) == 0 {
return []*GiftReceive{}, nil
}
//
giftIds := []mysql.ID{}
for i := 0; i < len(giftCountUsers); i++ {
giftIds = append(giftIds, giftCountUsers[i].ResGiftId)
}
//
gifts := []res_m.ResGift{}
if err := mysql.Db.Model(&res_m.ResGift{}).Where("id in (?)", giftIds).Find(&gifts).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//转换成map
mapGift := map[mysql.ID]res_m.ResGift{}
for i := 0; i < len(gifts); i++ {
mapGift[gifts[i].GetID()] = gifts[i]
}
//
giftReceives := []*GiftReceive{}
for i := 0; i < len(giftCountUsers); i++ {
gift := mapGift[giftCountUsers[i].ResGiftId]
giftReceives = append(giftReceives, &GiftReceive{
Name: StrToString(&gift.Name),
IconUrl: StrToString(&gift.IconUrl),
SvagUrl: StrToString(&gift.SvagUrl),
MusicUrl: StrToString(&gift.MusicUrl),
Num: NumToUint32(&giftCountUsers[i].Num),
TotolPrice: uint32(giftCountUsers[i].Num) * uint32(gift.DiamondNum),
})
}
sort.Sort(GiftReceives(giftReceives))
return giftReceives, nil
}
/**
* 礼物操作
**/
type GiftOperate struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResGiftId mysql.ID
GiftN mysql.Num
SendUserId mysql.ID
ReceiveUserId mysql.ID
SendUserDiamond mysql.Num
ReceiveUserDiamond mysql.Num
ReceiveUserBean mysql.Num
SceneType gift_e.GiftOperateSceneType
SceneUid mysql.Str
}
/*func (g *GiftOperate) GetConsumeSummary(beginDate, endDate string) (map[string]uint64, error) {
type summary struct {
SceneUid string
Sum uint64
}
rows := make([]summary, 0)
err := mysql.Db.Model(&GiftOperate{}).
Select("scene_uid, SUM(send_user_diamond) AS sum").
Where("scene_type = ? AND created_time >= ? AND DATE(created_time) <= ?", g.SceneType, beginDate, endDate).
Group("scene_uid").Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[string]uint64, len(rows))
for _, i := range rows {
result[i.SceneUid] = i.Sum
}
return result, err
}*/
//
func (g *GiftOperate) GetConsumeSummary(now time.Time, dayWeekMonth string) (map[string]uint64, error) {
key := ""
if dayWeekMonth == "day" {
key = redis_key.GetGiftOperateDay(now.Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "week" {
key = redis_key.GetGiftOperateWeek(utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "month" {
key = redis_key.GetGiftOperateMonth(now.Format(utils.COMPACT_MONTH_FORMAT))
}
if key == "" {
return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
}
zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
result := make(map[string]uint64, len(zs))
for _, r := range zs {
result[r.Member.(string)] = uint64(r.Score)
}
return result, nil
}
func (g *GiftOperate) GetRangeConsumeSummary(beginTime, endTime time.Time, groupIds []string) (map[string]uint64, error) {
result := make(map[string]uint64, len(groupIds))
for i, _ := range groupIds {
//移除过期的
key := redis_key.GetGiftOperate1HourDurationGroupId(groupIds[i])
if err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), key, "0", strconv.FormatInt(beginTime.Unix(), 10)).Err(); err != nil {
return nil, myerr.WrapErr(err)
}
//获取全部值,进行累加
strs, err := redisCli.GetRedis().ZRange(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
//
var total uint64 = 0
for j, _ := range strs {
score, err := strconv.ParseUint(strs[j], 10, 64)
if err != nil {
//异常则不退出
g.Log.Errorf("GetRangeConsumeSummary ParseUint err:%v, str:%v", err, strs[j])
} else {
total = total + score
}
}
result[groupIds[i]] = total
}
return result, nil
}
// 利用redis pipeline获取
func (g *GiftOperate) GetRangeConsumeSummaryV2(beginTime, endTime time.Time, groupIds []string) (map[string]uint64, error) {
ctx := context.Background()
result := make(map[string]uint64, len(groupIds))
strss := make([]*redis2.StringSliceCmd, len(groupIds))
_, err := redisCli.GetRedis().Pipelined(ctx, func(pipe redis2.Pipeliner) error {
for i := range groupIds {
//移除过期的
key := redis_key.GetGiftOperate1HourDurationGroupId(groupIds[i])
if err := pipe.ZRemRangeByScore(ctx, key, "0", strconv.FormatInt(beginTime.Unix(), 10)).Err(); err != nil {
return myerr.WrapErr(err)
}
//获取全部值,进行累加
strss[i] = pipe.ZRange(ctx, key, 0, -1)
}
return nil
})
for i, cmd := range strss {
strs, err := cmd.Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
var total uint64 = 0
for j, _ := range strs {
score, err := strconv.ParseUint(strs[j], 10, 64)
if err != nil {
//异常则不退出
g.Log.Errorf("GetRangeConsumeSummary ParseUint err:%v, str:%v", err, strs[j])
} else {
total = total + score
}
}
result[groupIds[i]] = total
}
return result, err
}
func GetGroupConsumeTotal(model *domain.Model, groupId string) (uint64, error) {
sum, err := group_c.GetGroupConsume(groupId)
if err == nil {
model.Log.Debugf("redis.GetGroupConsume, groupId: %s, sum = %d", groupId, sum)
return sum, nil
}
rmc := group_m.RoomMonthConsume{GroupId: groupId}
result, err := rmc.GetTotalDiamond(model.Db)
if err != nil {
return 0, err
}
err = group_c.SetGroupConsume(groupId, result, time.Minute)
model.Log.Debugf("redis.SetGroupConsume, groupId: %s, err:%v", groupId, err)
return result, nil
}
func (g *GiftOperate) GetGroupConsumeSummary(groupId string, now time.Time, dayWeekMonth string) (map[uint64]uint64, error) {
key := ""
if dayWeekMonth == "day" {
key = redis_key.GetGiftOperateGroupUidDay(groupId, now.Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "week" {
key = redis_key.GetGiftOperateGroupUidWeek(groupId, utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "month" {
key = redis_key.GetGiftOperateGroupUidMonth(groupId, now.Format(utils.COMPACT_MONTH_FORMAT))
}
if key == "" {
return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
}
zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
if err != nil {
if err == redis2.Nil {
return map[uint64]uint64{}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
sendUserMap := map[uint64]uint64{}
for _, r := range zs {
userId, err := strconv.ParseUint(r.Member.(string), 10, 64)
if err != nil {
return nil, myerr.WrapErr(err)
}
sendUserMap[userId] = uint64(r.Score)
}
return sendUserMap, nil
}
func (g *GiftOperate) GetGroupReceiveSummary(groupId string, now time.Time, dayWeekMonth string) (map[uint64]uint64, error) {
key := ""
if dayWeekMonth == "day" {
key = redis_key.GetGiftOperateReceiveGroupUidDay(groupId, now.Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "week" {
key = redis_key.GetGiftOperateReceiveGroupUidWeek(groupId, utils.GetMonday(now).Format(utils.COMPACT_DATE_FORMAT))
} else if dayWeekMonth == "month" {
key = redis_key.GetGiftOperateReceiveGroupUidMonth(groupId, now.Format(utils.COMPACT_MONTH_FORMAT))
}
if key == "" {
return nil, myerr.NewSysErrorF("GetConsumeSummary dayWeekMonth:%v, no find")
}
zs, err := redisCli.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, 29).Result()
if err != nil {
if err == redis2.Nil {
return map[uint64]uint64{}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
receiveUserMap := map[uint64]uint64{}
for _, r := range zs {
userId, err := strconv.ParseUint(r.Member.(string), 10, 64)
if err != nil {
return nil, myerr.WrapErr(err)
}
receiveUserMap[userId] = uint64(r.Score)
}
return receiveUserMap, nil
}
//type PendingInteraction struct {
// user_cv.CvUserTiny
// RecordType uint8 `json:"recordType"` // 记录类型:1、礼物,2、视频
// SendTime int64 `json:"sendTime"` // 送礼物/视频的时间
//}
func StrToString(str *mysql.Str) *string {
return (*string)(str)
}
func NumToUint32(num *mysql.Num) *uint32 {
return (*uint32)(num)
}
package group_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/utils"
"hilo-group/_const/enum/game_e"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/online_e"
"hilo-group/cv/billboard_cv"
"hilo-group/cv/group_power_cv"
"hilo-group/cv/medal_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m"
"hilo-group/domain/service/group_s"
"sort"
)
type GroupBasicInfo struct {
Id int64 `json:"id,omitempty"`
GroupId string `json:"groupId"`
Name string `json:"name"`
Introduction string `json:"introduction"`
Notification string `json:"notification"`
FaceUrl string `json:"faceUrl"`
Owner_Account string `json:"ownerAccount"`
CreateTime int `json:"createTime"`
//LastInfoTime int `json:"last_info_time"`
LastMsgTime int `json:"lastMsgTime"`
NextMsgSeq uint `json:"nextMsgSeq"`
MemberNum uint `json:"memberNum"`
MaxMemberNum uint `json:"maxMemberNum"`
ShutUpAllMember string `json:"shutUpAllMember"`
Code string `json:"code"`
Password *string `json:"password"`
CountryIcon string `json:"countryIcon"`
SupportLevel uint8 `json:"supportLevel"` // 本周最高的扶持等级
//1:5人 2:10人
MicNumType int `json:"micNumType"`
// N天内的进入用户数量(重复进入去重,实时)
GroupInUserDuration int64 `json:"groupInUserDuration"`
GroupMedals []medal_cv.PicElement `json:"groupMedals"` // 群勋章
TouristMic uint8 `json:"touristMic"` // 游客是否能上麦
TouristSendMsg uint8 `json:"touristSendMsg"` // 游客是否能发言
TouristSendPic uint8 `json:"touristSendPic"` // 游客是否能发图片
MemberFee uint64 `json:"memberFee"` // 加入群组会员需要的黄钻
}
type MemberListInfo struct {
Member_Account string `json:"memberAccount"`
JoinTime int `json:"joinTime"`
//MsgSeq uint `json:"msg_seq"`
LastSendMsgTime int64 `json:"lastSendMsgTime"`
//ShutUpUntil int `json:"shut_up_until"`
// AppMemberDefinedData": [ // 群成员自定义字段 【暂时不用】
}
type GroupInfo struct {
GroupBasicInfo
// hilo业务
EntryLevel uint32 `json:"entryLevel"` // obsolete
HasOnMic bool `json:"hasOnMic"` // 房间麦上是否有人
GroupPowerId uint64 `json:"groupPowerId"` // 群主所在的势力ID
GroupPowerName string `json:"groupPowerName"` // 群主所在的势力的名称
// "AppDefinedData": 群组维度的自定义字段 【暂时不用】
MemberList []MemberListInfo
}
type PopularGroupInfo struct {
GroupInfo
MicUsers []user_cv.CvUserTiny `json:"micUsers"` // 在麦上的用户,最多4个
RoomUserCount uint `json:"roomUserCount"` // 当前在房间的用户数
MaxStage *uint16 `json:"maxStage"` // 今天爆过的最大的火箭
GameTypes []game_e.GameType `json:"gameTypes,omitempty"` // 房间内正在进行的游戏 1:ludo 2:uno
}
// 最新的群组列表, 字段暂时应该跟popular一样
type LatestGroupInfo PopularGroupInfo
type TheirGroupsInfo struct {
Total uint `json:"total"`
OwnGroups []JoinedGroupInfo `json:"ownGroups"`
Groups []JoinedGroupInfo `json:"groups"`
}
type JoinedGroupInfo struct {
PopularGroupInfo
LastEnterTime int64 `json:"lastEnterTime"` // 最后一次进房间的时间
}
type JoinedGroupRsp struct {
Total uint `json:"total"`
Groups []JoinedGroupInfo `json:"groups"`
}
type RoleMemberInfo struct {
user_cv.CvUserBase
Role group_e.GroupRoleType `json:"role"`
OnlineStatus online_e.OnlineStatusType `json:"onlineStatus"`
}
type MemberDetail struct {
user_cv.CvUserExtend
Role group_e.GroupRoleType `json:"role"`
OnlineStatus online_e.OnlineStatusType `json:"onlineStatus"` // IM在线状态
InRoom bool `json:"inRoom"` // 是否在房间内
}
type GroupDetail struct {
GroupBasicInfo
// hilo业务
EntryLevel uint32 `json:"entryLevel"` // obsolete
MicOn bool `json:"micOn"`
LoadHistory bool `json:"loadHistory"`
ThemeId uint64 `json:"themeId"`
ThemeUrl string `json:"themeUrl"`
// 1:官方 2:自定义
ThemeType uint8 `json:"themeType"`
Role group_e.GroupRoleType `json:"role"`
MsgStatus uint8 `json:"msgStatus"` // 消息提醒状态
WelcomeText string `json:"welcomeText"` // 新成员入群欢迎语
TotalConsume uint64 `json:"totalConsume"` // 群内消费总额
TopConsumers []billboard_cv.BillboardUserInfo `json:"topConsumers"` // 月最高消费三甲
DiceNum uint16 `json:"diceNum"` // 骰子游戏的数量
DiceType uint16 `json:"diceType"` // 骰子游戏的数字点数
// "AppDefinedData": 群组维度的自定义字段 【暂时不用】
RoleMembers []RoleMemberInfo `json:"role_members"`
Owner *user_cv.CvUserDetail `json:"owner"` // 群主信息
}
type SimpleRoleInfo struct {
ExternalId string `json:"externalId"`
Role group_e.GroupRoleType `json:"role"`
}
type BannerElement struct {
H5Url string `json:"h5Url"` // h5链接
BannerUrl string `json:"bannerUrl"` // 图片地址
}
type RoomInfo struct {
GroupBasicInfo
// hilo业务
MicOn bool `json:"micOn"`
LoadHistory bool `json:"loadHistory"`
ThemeId uint64 `json:"themeId"`
ThemeUrl string `json:"themeUrl"`
// 1:官方 2:自定义
ThemeType uint8 `json:"themeType"`
Role group_e.GroupRoleType `json:"role"`
DiceNum uint16 `json:"diceNum"` // 骰子游戏的数量
DiceType uint16 `json:"diceType"` // 骰子游戏类型
RoleMembers []SimpleRoleInfo `json:"roleMembers"`
WelcomeText string `json:"welcomeText"` // 新成员入群欢迎语
Banners []BannerElement `json:"banners"`
LuckyWheel LuckyWheelState `json:"luckyWheel"`
TotalConsume uint64 `json:"totalConsume"`
GameConfig *game_m.GameConfig `json:"gameConfig"`
Owner *user_cv.CvUserDetail `json:"owner"`
}
type SupportPageDetail struct {
GroupId string `json:"groupId"`
CurrentConsume uint64 `json:"currentConsume"` // 当前周期的消费额(钻石)
CurrentCount uint32 `json:"currentCount"` // 当前周期的消费人数
LastConsume uint64 `json:"lastConsume"` // 上一个周期的消费额(钻石)
LastCount uint32 `json:"lastCount"` // 上一个周期的消费人数
SupportLevel string `json:"supportLevel"` // 上一个周期(已结算)的支持等级
SupporterLimit uint32 `json:"supporterLimit"` // 上一个周期(已结算)的支持者的上限
CurrentSupportLevel string `json:"currentSupportLevel"` // 当前的支持等级
RemainSecond int64 `json:"remainSecond"` // 离下一次结算还有多少秒
ProfitAllocator user_cv.CvUserBase `json:"profitAllocator"` // 利益分配人,群主或由运营指定(官方群)
Supporters []user_cv.CvUserBase `json:"supporters"` // 扶持管理员
IsDispatched bool `json:"isDispatched"` // 奖励是否已经分配
}
type AwardResult struct {
Success []string `json:"success"`
Failed []string `json:"failed"`
}
type GroupPowerTitle struct {
Id uint64 `json:"id"`
Name string `json:"name"`
GroupId string `json:"groupId"` // 势力的主群
Avatar string `json:"avatar"`
MemberNum uint `json:"memberNum"` // 成员人数
Owner user_cv.CvUserBase `json:"owner"` // 势力主
Assistants []user_cv.CvUserBase `json:"assistants"` // 势力助手,目前就是主群的管理
IsMyGroupPower bool `json:"isMyGroupPower"` // “我”是否属于这个势力
}
type RoomMedalInfo struct {
Level uint16 `json:"level"`
PreviewUrl string `json:"previewUrl"`
PicUrl string `json:"picUrl"`
Desc string `json:"desc"`
}
func BuildJoinedGroupInfo(myService *domain.Service, myUserId uint64, groupIds []string, pageSize, pageIndex int) ([]JoinedGroupInfo, int, error) {
model := domain.CreateModel(myService.CtxAndDb)
groupInfo, err := group_m.BatchGetGroupInfo(model, groupIds)
if err != nil {
return nil, 0, err
}
// todo: 可以移到后面,减小查询范围,因为roomMicUserMap不影响排序
roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds)
if err != nil {
return nil, 0, err
}
uids := make([]uint64, 0)
micUsersMap := make(map[string][]uint64, 0)
for _, i := range groupInfo {
micUsersMap[i.ImGroupId] = make([]uint64, 0)
if len(i.Password) <= 0 {
// 密码群不显示麦上头像
u := roomMicUserMap[i.ImGroupId]
if len(u) >= 4 {
micUsersMap[i.ImGroupId] = u[0:4]
} else if len(u) > 0 {
micUsersMap[i.ImGroupId] = u
}
uids = append(uids, micUsersMap[i.ImGroupId]...)
}
}
uids = utils.UniqueSliceUInt64(uids)
userTiny, err := user_cv.GetUserTinyMap(uids)
if err != nil {
return nil, 0, err
}
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, 0, err
}
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return nil, 0, err
}
supportLevels, err := group_s.NewGroupService(model.MyContext).GetWeekMaxSupportLevelMap()
if err != nil {
return nil, 0, err
}
visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
if err != nil {
return nil, 0, err
}
roomEnterTime, err := room_c.GetUserRoomVisit(myUserId)
if err != nil {
return nil, 0, err
}
model.Log.Infof("BuildJoinedGroupInfo, roomEnterTime: %v", roomEnterTime)
// 排序优先级V8.0版本
sort.Slice(groupIds, func(i, j int) bool {
gi := groupIds[i]
gj := groupIds[j]
return roomEnterTime[gi] > roomEnterTime[gj] ||
roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] > visitCount[gj] ||
roomEnterTime[gi] == roomEnterTime[gj] && visitCount[gj] == visitCount[gj] && i >= j
})
result := make([]JoinedGroupInfo, 0)
beginPos := pageSize * (pageIndex - 1)
endPos := pageSize * pageIndex
if beginPos < len(groupIds) {
if endPos > len(groupIds) {
endPos = len(groupIds)
}
groupIds = groupIds[beginPos:endPos]
owners := make([]uint64, 0)
for _, i := range groupIds {
owners = append(owners, groupInfo[i].Owner)
}
powerIds, powerNames, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return nil, 0, err
}
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return nil, 0, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return nil, 0, err
}
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(model.Db, groupIds)
if err != nil {
return nil, 0, err
}
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
for _, i := range groupIds {
g := groupInfo[i]
micUsers := make([]user_cv.CvUserTiny, 0)
for _, j := range micUsersMap[i] {
micUsers = append(micUsers, userTiny[j])
}
var maxStage *uint16 = nil
if s, ok := maxStageMap[i]; ok {
maxStage = &s
}
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[i]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
}
}
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, i)
if err != nil {
model.Log.Infof("BuildJoinedGroupInfo: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
var password *string = nil
if len(g.Password) > 0 && g.Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
result = append(result, JoinedGroupInfo{
PopularGroupInfo: PopularGroupInfo{
GroupInfo: GroupInfo{
GroupBasicInfo: GroupBasicInfo{
GroupId: g.TxGroupId,
Name: g.Name,
Notification: g.Notification,
Introduction: g.Introduction,
FaceUrl: g.FaceUrl,
Code: g.Code,
CountryIcon: countryInfo[g.Country],
Password: password,
SupportLevel: supportLevels[i],
GroupInUserDuration: visitCount[i],
MicNumType: int(g.MicNumType),
GroupMedals: medals,
},
HasOnMic: len(micUsers) > 0,
GroupPowerId: powerIds[g.Owner],
GroupPowerName: powerNames[g.Owner],
},
MicUsers: micUsers,
RoomUserCount: uint(roomCount[i]),
MaxStage: maxStage,
GameTypes: games[g.TxGroupId],
},
LastEnterTime: roomEnterTime[i],
})
}
}
return result, len(groupInfo), nil
}
package group_cv
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
"hilo-group/_const/enum/luckyWheel_e"
"hilo-group/cv/user_cv"
"hilo-group/domain/model/luckyWheel_m"
"hilo-group/myerr/bizerr"
"time"
)
type ResLuckyWheel struct {
Id uint `json:"id"`
EntranceFee uint32 `json:"entranceFee"`
}
func GetAllLuckyWheelConfig(db *gorm.DB) ([]ResLuckyWheel, error) {
rows := make([]ResLuckyWheel, 0)
if err := db.Model(&ResLuckyWheel{}).Order("id").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (rlw *ResLuckyWheel) GetLuckyWheelConfig(db *gorm.DB) error {
return db.Where(rlw).First(rlw).Error
}
type LuckyWheelUserOption struct {
UserId uint64 `json:"-"`
GroupId string `json:"-"`
LastId uint `json:"lastId"` // 最后一次选择的配置ID
SelfJoin bool `json:"selfJoin"` // 自己是否加入
AutoRestart bool `json:"autoRestart"` // 是否重新开始新的一轮
}
func (uo *LuckyWheelUserOption) Get(db *gorm.DB) error {
return db.Where(uo).First(uo).Error
}
type LuckyWheelSetting struct {
Config []ResLuckyWheel `json:"config"` // 配置
LuckyWheelUserOption
}
type LuckyWheelState struct {
WheelId uint64 `json:"wheelId"` // 当前轮盘ID;=0时代表没有轮盘活动,其他参数都不用看了
Status uint8 `json:"status"` // 轮盘状态
EntranceFee uint32 `json:"entranceFee"` // 参与费用(钻石)
Creator string `json:"creator"` // 当前轮盘创建者(exteranlId)
SeatNum uint `json:"seatNum"` // 轮盘位置数
Participants []user_cv.CvUserTiny `json:"participants"` // 轮盘参与者信息
TotalFee uint32 `json:"totalFee"` // 总参与金额
PlayTimeStamp int64 `json:"playTimeStamp"` // 轮盘开始转动的时刻
Sequence []string `json:"sequence"` // 出局序列(用户externalId)
LosersNum int `json:"losersNum"` // 出局人数,最多是N-1
WinnerAmount uint32 `json:"winnerAmount"` // 胜利都得到的钻石数
}
func GetLuckWheelState(model *domain.Model, groupId string) (LuckyWheelState, error) {
result := LuckyWheelState{}
// FIXME: 先查redis,减少DB访问
lw := luckyWheel_m.LuckyWheel{GroupId: groupId}
err := lw.Get(model.Db)
if err != nil && err != gorm.ErrRecordNotFound {
return result, err
}
if err == gorm.ErrRecordNotFound {
result.WheelId = 0
result.Status = luckyWheel_e.NONE
} else {
uids := []uint64{lw.Creator}
lws := luckyWheel_m.LuckyWheelSeat{WheelId: lw.ID}
seats, err := lws.Get(model.Db)
if err != nil && err != gorm.ErrRecordNotFound {
return result, err
}
for _, i := range seats {
uids = append(uids, i.UserId)
}
userMap, err := user_cv.GetUserTinyMap(uids)
if err != nil {
return result, err
}
result = LuckyWheelState{
WheelId: lw.ID,
Status: lw.Status,
EntranceFee: lw.EntranceFee,
Creator: userMap[lw.Creator].ExternalId,
SeatNum: luckyWheel_e.LUCKY_WHEEL_SEAT_NUM,
PlayTimeStamp: lw.PlayTime.Unix(),
}
for _, i := range seats {
result.Participants = append(result.Participants, userMap[i.UserId])
}
result.TotalFee = result.EntranceFee * uint32(len(result.Participants))
if result.Status == luckyWheel_e.ROLLING || result.Status == luckyWheel_e.SHOWING {
result.Sequence = make([]string, len(seats), len(seats))
for _, e := range seats {
if e.SeqId > 0 && e.SeqId <= uint(len(seats)) {
result.Sequence[e.SeqId-1] = userMap[e.UserId].ExternalId
} else {
// FIXME:怎么办!?
}
}
model.Log.Infof("Group %s, wheel %d, result: %v", groupId, lw.ID, result.Sequence)
}
if result.Status == luckyWheel_e.ROLLING {
now := time.Now()
if now.After(lw.PlayTime) {
timeDiff := now.Unix() - lw.PlayTime.Unix()
n := timeDiff / luckyWheel_e.LUCKY_WHEEL_ROLL_TIME
if n >= int64(len(result.Participants))-2 {
remain := timeDiff - luckyWheel_e.LUCKY_WHEEL_ROLL_TIME*n
if remain >= luckyWheel_e.LUCKY_WHEEL_LAST_ROLL_TIME {
n++
}
}
result.LosersNum = int(n)
if result.LosersNum >= len(result.Participants)-1 {
result.LosersNum = len(result.Participants) - 1
}
}
result.WinnerAmount, _ = luckyWheel_m.CalcDiamond(lw.EntranceFee, len(result.Participants))
} else if result.Status == luckyWheel_e.SHOWING {
result.LosersNum = len(result.Participants)
}
if result.Status == luckyWheel_e.SHOWING || result.Status == luckyWheel_e.RESTARTING {
lwh := luckyWheel_m.LuckyWheelHistory{WheelId: lw.ID}
err = lwh.Get(model.Db)
if err == nil {
result.WinnerAmount = lwh.WinnerAward
} else if err != gorm.ErrRecordNotFound {
return result, bizerr.IncorrectState
}
}
}
return result, nil
}
package group_power_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/domain/model/groupPower_m"
)
func BatchGetGroupPower(db *gorm.DB, userIds []uint64) (map[uint64]uint64, map[uint64]string, error) {
if len(userIds) <= 0 {
return nil, nil, nil
}
groupPowers, err := groupPower_m.GetGroupPowerMap(db, userIds)
if err != nil {
return nil, nil, err
}
gpIds := make([]uint64, 0)
for _, i := range groupPowers {
gpIds = append(gpIds, i)
}
powerNames, err := groupPower_m.GetGroupPowerNames(db, gpIds)
if err != nil {
return nil, nil, err
}
groupPowerNames := make(map[mysql.ID]string, 0)
for i, g := range groupPowers {
groupPowerNames[i] = powerNames[g]
}
return groupPowers, groupPowerNames, nil
}
package headwear_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/headwear_e"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/myerr"
"strconv"
"time"
)
type CvHeadwear struct {
Id uint64 `json:"id"`
Using bool `json:"using"`
PicUrl mysql.Str `json:"picUrl"`
EffectUrl mysql.Str `json:"effectUrl"`
TimeLeft int64 `json:"timeLeft"` // 离到期还有多少秒(过期则是负数)
}
type CvHeadwearDiamond struct {
Id uint64 `json:"id"`
PicUrl string `json:"picUrl"`
EffectUrl string `json:"effectUrl"`
DiamondNum uint32 `json:"diamondNum"`
Second uint32 `json:"second"`
Days string `json:"days"`
}
func GetCvHeadwearDiamond(pageSize int, pageIndex int) ([]CvHeadwearDiamond, error) {
headwearDiamonds := []CvHeadwearDiamond{}
if err := mysql.Db.Raw("SELECT d.id, r.pic_url, r.effect_url, d.`second`, d.diamond_num from res_headwear r, res_headwear_diamond d where r.id = d.res_headwear_id and d.`status` = ? ORDER BY d.diamond_num asc LIMIT ?, ?", mysql.USER, (pageIndex-1)*pageSize, pageSize).Scan(&headwearDiamonds).Error; err != nil {
return nil, myerr.WrapErr(err)
}
for i, _ := range headwearDiamonds {
headwearDiamonds[i].Days = strconv.FormatUint(uint64(headwearDiamonds[i].Second/(24*60*60)), 10)
}
return headwearDiamonds, nil
}
func GetHeadwearList(db *gorm.DB, userId uint64) ([]CvHeadwear, error) {
rows := make([]user_m.UserHeadwear, 0)
if err := db.Where(&user_m.UserHeadwear{
UserId: userId,
}).Where("end_time >= ?", time.Now()).Order("`using` DESC, updated_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
resHwMap, err := res_m.GetResHeadwearMap(db)
if err != nil {
return nil, myerr.WrapErr(err)
}
result := make([]CvHeadwear, 0)
now := time.Now()
hasUsing := false
for _, i := range rows {
// TODO: 没过期并且有设置using的,才算是,因为写入方不维护using状态的更新
isUsing := i.Using == headwear_e.YesUsing && i.EndTime.After(now)
result = append(result, CvHeadwear{
Id: i.HeadwearId,
PicUrl: resHwMap[i.HeadwearId].PicUrl,
EffectUrl: resHwMap[i.HeadwearId].EffectUrl,
Using: isUsing,
TimeLeft: i.EndTime.Unix() - now.Unix(),
})
if isUsing {
hasUsing = true
}
}
// 如果没有一个using,则找第一个没过期的充当
if ! hasUsing {
for i, e := range result {
if e.TimeLeft > 0 {
result[i].Using = true
break
}
}
}
return result, nil
}
func GetCvHeadwear(userId uint64) (*CvHeadwear, error) {
userHeadwear := user_m.UserHeadwear{}
if err := mysql.Db.Model(&user_m.UserHeadwear{}).Where(&user_m.UserHeadwear{
UserId: userId,
}).Where("end_time >= ?", time.Now()).Order("`using` DESC, updated_time DESC").First(&userHeadwear).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resHeadwear := res_m.ResHeadwear{}
if err := mysql.Db.Model(&res_m.ResHeadwear{}).First(&resHeadwear, userHeadwear.HeadwearId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
return &CvHeadwear{
Id: userHeadwear.HeadwearId,
PicUrl: resHeadwear.PicUrl,
EffectUrl: resHeadwear.EffectUrl,
Using: userHeadwear.Using == headwear_e.YesUsing,
}, nil
}
func BatchGetCvHeadwears(userIds []uint64) (map[uint64]CvHeadwear, error) {
if len(userIds) == 0 {
return map[uint64]CvHeadwear{}, nil
}
rows := make([]user_m.UserHeadwear, 0)
//asc 进行覆盖,保证了updated_time 最大的是最后的输出
if err := mysql.Db.Where("user_id IN ?", userIds).Where("end_time >= ?", time.Now()).
Order("`using` ASC, updated_time ASC").Find(&rows).Error; err != nil {
return nil, err
}
//
resHeadwearIds := make([]uint64, 0, len(rows))
for i, _ := range rows {
resHeadwearIds = append(resHeadwearIds, rows[i].HeadwearId)
}
//获取头饰资源,然后转换成map结构
resHeadwearMap := map[uint64]res_m.ResHeadwear{}
resHeadwears := []res_m.ResHeadwear{}
if err := mysql.Db.Where("id IN ?", resHeadwearIds).Find(&resHeadwears).Error; err != nil {
return nil, err
}
for i, _ := range resHeadwears {
resHeadwearMap[resHeadwears[i].ID] = resHeadwears[i]
}
result := make(map[uint64]CvHeadwear, 0)
for _, r := range rows {
headwear, flag := resHeadwearMap[r.HeadwearId]
if flag {
result[r.UserId] = CvHeadwear{
Id: headwear.ID,
PicUrl: headwear.PicUrl,
EffectUrl: headwear.EffectUrl,
Using: r.Using == headwear_e.YesUsing,
}
}
}
return result, nil
}
package medal_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/cv/gift_cv"
"hilo-group/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"`
}
// 查询群流水勋章
func GetGroupConsumeMedal(model *domain.Model, groupId string) (uint64, *PicElement, error) {
consumeTotal, err := gift_cv.GetGroupConsumeTotal(model, groupId)
if err != nil {
return 0, nil, err
}
rec, err := res_m.GetRoomMedalConfig(model.Db)
if err != nil {
return consumeTotal, nil, err
}
// 只显示最高等级的,所以要倒序遍历
for i := len(rec) - 1; i >= 0; i-- {
if consumeTotal >= rec[i].Threshold {
return consumeTotal, &PicElement{PicUrl: rec[i].ActiveUrl}, nil
}
}
return consumeTotal, nil, nil
}
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-group/domain/model/noble_m"
"hilo-group/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
}
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-group/_const/enum/headwear_e"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/myerr"
"strconv"
"time"
)
type CvProperty struct {
Id uint64 `json:"id"`
PicUrl mysql.Str `json:"picUrl"`
EffectUrl mysql.Str `json:"effectUrl"`
Using bool `json:"using"`
TimeLeft int64 `json:"timeLeft"` // 离到期还有多少秒(过期则是负数)
SenderAvatar string `json:"senderAvatar"`
ReceiverAvatar string `json:"receiverAvatar"`
}
type CvPropertyDiamond struct {
Id uint64 `json:"id"`
PicUrl string `json:"picUrl"`
EffectUrl string `json:"effectUrl"`
DiamondNum uint32 `json:"diamondNum"`
Second uint32 `json:"second"`
Days string `json:"days"`
}
func GetCvPropertyDiamond(pageSize int, pageIndex int) ([]CvPropertyDiamond, error) {
propertyDiamonds := []CvPropertyDiamond{}
if err := mysql.Db.Raw("select d.id, r.pic_url, r.effect_url, d.`second`, d.diamond_num from res_property r, res_property_diamond d where r.id = d.res_property_id and d.`status` = ? ORDER BY d.diamond_num ASC LIMIT ?, ?", mysql.USER, (pageIndex-1)*pageSize, pageSize).Scan(&propertyDiamonds).Error; err != nil {
return nil, myerr.WrapErr(err)
}
for i, _ := range propertyDiamonds {
propertyDiamonds[i].Days = strconv.FormatUint(uint64(propertyDiamonds[i].Second/(24*60*60)), 10)
}
return propertyDiamonds, nil
}
func GetPropertyById(resPropertyId mysql.ID) (CvProperty, error) {
resProperty := res_m.ResProperty{}
if err := mysql.Db.Model(&res_m.ResProperty{}).First(&resProperty, resPropertyId).Error; err != nil {
return CvProperty{}, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
if err != nil {
return CvProperty{}, err
}
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := mysql.Db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return CvProperty{}, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[resProperty.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
return CvProperty{
Id: resProperty.ID,
PicUrl: resProperty.PicUrl,
EffectUrl: resProperty.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}, nil
}
func GetPropertyAll(db *gorm.DB) (map[uint64]CvProperty, error) {
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := map[uint64]CvProperty{}
for _, r := range properties {
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[r.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result[r.ID] = CvProperty{
Id: r.ID,
PicUrl: r.PicUrl,
EffectUrl: r.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}
}
return result, nil
}
func GetPropertyList(db *gorm.DB, userId uint64) ([]CvProperty, error) {
rows := make([]user_m.UserProperty, 0)
if err := db.Where(&user_m.UserProperty{
UserId: userId,
}).Order("`using` DESC, updated_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := make([]CvProperty, 0)
now := time.Now()
hasUsing := false
for _, i := range rows {
// TODO: 没过期并且有设置using的,才算是,因为写入方不维护using状态的更新
isUsing := i.Using == headwear_e.YesUsing && i.EndTime.After(now)
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[i.PropertyId]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result = append(result, CvProperty{
Id: i.PropertyId,
PicUrl: properties[i.PropertyId].PicUrl,
EffectUrl: properties[i.PropertyId].EffectUrl,
Using: isUsing,
TimeLeft: i.EndTime.Unix() - now.Unix(),
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
})
if isUsing {
hasUsing = true
}
}
// 如果没有一个using,则找第一个没过期的充当
if !hasUsing {
for i, e := range result {
if e.TimeLeft > 0 {
result[i].Using = true
break
}
}
}
return result, nil
}
package user_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/domain/model/user_m"
)
// 批量获取财富等级
func BatchGetWealthGrade(userIds []mysql.ID) (map[mysql.ID]uint32, error) {
rows := make([]user_m.MatchWealthUserScore, 0)
err := mysql.Db.Model(&user_m.MatchWealthUserScore{}).Where("user_id IN ?", userIds).Find(&rows).Error
if err == nil {
result := make(map[mysql.ID]uint32, 0)
for _, i := range rows {
result[i.UserId] = i.Grade
}
return result, nil
} else {
return nil, err
}
}
// 批量获取魅力等级
func BatchGetCharmGrade(userIds []mysql.ID) (map[mysql.ID]uint32, error) {
rows := make([]user_m.MatchCharmUserScore, 0)
err := mysql.Db.Model(&user_m.MatchCharmUserScore{}).Where("user_id IN ?", userIds).Find(&rows).Error
if err == nil {
result := make(map[mysql.ID]uint32, 0)
for _, i := range rows {
result[i.UserId] = i.Grade
}
return result, nil
} else {
return nil, err
}
}
// 批量获取活跃等级
func BatchGetActiveGrade(userIds []mysql.ID) (map[mysql.ID]uint32, error) {
rows := make([]user_m.MatchActityUserScore, 0)
err := mysql.Db.Model(&user_m.MatchActityUserScore{}).Where("user_id IN ?", userIds).Find(&rows).Error
if err == nil {
result := make(map[mysql.ID]uint32, 0)
for _, i := range rows {
result[i.UserId] = i.Grade
}
return result, nil
} else {
return nil, err
}
}
package user_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/user_e"
"hilo-group/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 BatchGetRelations(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 = mysql.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 > user_e.HEART_VALUE_MAX {
i.HeartValue = user_e.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: user_e.HEART_VALUE_MAX, MeetDays: d}
}
rows = make([]UserRelation, 0)
if len(smaller) > 0 {
if err = mysql.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 > user_e.HEART_VALUE_MAX {
i.HeartValue = user_e.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: user_e.HEART_VALUE_MAX, MeetDays: d}
}
// 补上没有成长关系的人
for _, u := range others {
if _, exists := result[u]; !exists {
result[u] = Relation{0, 0, 0}
}
}
return result, err
}
// 查询成长关系
func GetRelation(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 := mysql.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 = user_e.HEART_VALUE_MAX
result.HeartValue = rel.HeartValue
if result.HeartValue > user_e.HEART_VALUE_MAX {
result.HeartValue = user_e.HEART_VALUE_MAX
}
d := uint(time.Since(rel.CreatedTime).Hours() / 24)
if d < 0 {
d = 0
}
result.MeetDays = d
return result, nil
}
package user_cv
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
. "git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/user_e"
"hilo-group/cv/country_cv"
"hilo-group/cv/diamond_cv"
"hilo-group/cv/headwear_cv"
"hilo-group/cv/medal_cv"
"hilo-group/cv/noble_cv"
"hilo-group/cv/property_cv"
"hilo-group/domain/model/groupPower_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/model/visit_m"
"hilo-group/myerr"
)
//用户详细信息
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"` // 当前用户所在势力绑定群组的名称
GroupId string `json:"groupId"` // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个
//PhoneInfo *model.UserPhoneInfo `json:"phoneInfo"` // 用户绑定的手机信息
ThirdList []int8 `json:"thirdList"` // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5)
CountryManager *country_cv.CVCountryManager `json:"countryManager,omitempty"` // 国家管理员
}
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 CvUserBase struct {
//不会有返回值
Id *mysql.ID `json:"id,omitempty"`
//头像,不存在为nil
Avatar *string `json:"avatar"`
//是否默认头像 true:是 false:不是
DefaultAvatar *bool `json:"defaultAvatar"`
//用户对外ID
ExternalId *string `json:"externalId"`
//昵称,不存在为nil
Nick *string `json:"nick"`
//签名,不存在为nil
Description *string `json:"description"`
//性别 1:男 2:女,不存在为nil
Sex *uint8 `json:"sex"`
//国家,不存在为nil
Country *string `json:"country"`
//国旗图标,不存在为nil
CountryIcon *string `json:"countryIcon"`
//邀请码
Code *string `json:"code"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
IsLogout bool `json:"isLogout"` //是否注销
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
//是否展示年龄, 是本人才有数据,看其他用户均为nil
IsShowAge *uint8 `json:"isShowAge"`
//是否工会成员, 只有是自己查自己,这个才有值,其它全为nil, 20220329 数据开放:原因:产品1对1视频聊天中,公会用户视频需要送礼物。改为: 全部人可以知道是否是公会用户。
IsTradeUnion *bool `json:"isTradeUnion"`
//是否代理管理员, 只有自己查自己的时候才有值,其他情况为nil
IsAgentMgr *bool `json:"isAgentMgr"`
//工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值,
IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"`
//是否VIP用户
IsVip bool `json:"isVip"`
//是否是官方人员
IsOfficialStaff bool `json:"isOfficialStaff"`
//VIP用户过期时间(只有自己查询自己,才返回)
VipExpireTime *int64 `json:"vipExpireTime"`
Svip rpc.CvSvip `json:"svip"` // svip结构,等级+权限
Medals []uint32 `json:"medals"` // 勋章列表 TODO: 删除
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 group_e.GroupRoleType `json:"groupRole"` // 在群组的角色
}
type CvUserExtend struct {
CvUserBase
WealthGrade uint32 `json:"wealthUserGrade"`
CharmGrade uint32 `json:"charmUserGrade"`
ActiveGrade uint32 `json:"activityUserGrade"`
}
// 批量获取用户tiny信息
func GetUserTinyMap(userIds []mysql.ID) (map[mysql.ID]CvUserTiny, error) {
userTinys, _, err := GetUserTinys(userIds)
if err != nil {
return nil, err
}
result := make(map[mysql.ID]CvUserTiny, 0)
for i, _ := range userTinys {
result[userTinys[i].Id] = userTinys[i]
}
return result, nil
}
//批量获取用户tiny信息
func GetUserTinys(userIds []mysql.ID) ([]CvUserTiny, []uint64, error) {
if len(userIds) == 0 {
return nil, nil, 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, nil, myerr.WrapErr(err)
}
userTinys := make([]CvUserTiny, 0, len(users))
for _, r := range users {
userTinys = append(userTinys, GetUserTinyBy(r))
}
return userTinys, userIds, nil
}
func GetUserTinyBy(user user_m.User) CvUserTiny {
return CvUserTiny{
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 GetUserDetailMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUserDetail, error) {
cvUserDetails, err := getUserDetailByIds(userIds, myUserId)
if err != nil {
return map[mysql.ID]*CvUserDetail{}, err
}
//转换成map
mapIdUser := map[mysql.ID]*CvUserDetail{}
for i := 0; i < len(cvUserDetails); i++ {
mapIdUser[*cvUserDetails[i].Id] = cvUserDetails[i]
}
return mapIdUser, nil
}
func getUserDetailByIds(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserDetail, error) {
if len(userIds) == 0 {
return nil, nil
}
model := domain.CreateModelNil()
var users []*user_m.User
if err := model.DB().Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
cvUserDetails, err := getUserDetails(model, users, myUserId)
if err != nil {
return nil, err
}
return cvUserDetails, nil
}
func getUserDetails(model *domain.Model, users []*user_m.User, myUserId mysql.ID) ([]*CvUserDetail, error) {
//找出所有user.id
userIds := []mysql.ID{}
for i := 0; i < len(users); i++ {
userIds = append(userIds, users[i].ID)
}
//查找喜欢
var userLikes []user_m.UserLike
if err := mysql.Db.Where(&user_m.UserLike{
UserId: myUserId,
}).Where("like_user_id in (?)", userIds).Find(&userLikes).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//喜欢组成map
likeMap := map[mysql.ID]bool{}
for i := 0; i < len(userLikes); i++ {
likeMap[userLikes[i].LikeUserId] = true
}
//查找喜欢我的
userLikeMes := []user_m.UserLike{}
if err := mysql.Db.Where(&user_m.UserLike{
LikeUserId: myUserId,
}).Where("user_id in (?)", userIds).Find(&userLikeMes).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//喜欢组成map
likeMeMap := map[mysql.ID]bool{}
for i := 0; i < len(userLikeMes); i++ {
likeMeMap[userLikeMes[i].UserId] = true
}
rels, _ := BatchGetRelations(myUserId, userIds)
wealthGradeMap, err := BatchGetWealthGrade(userIds)
if err != nil {
return nil, err
}
charmGradeMap, err := BatchGetCharmGrade(userIds)
if err != nil {
return nil, err
}
activeGradeMap, err := BatchGetActiveGrade(userIds)
if err != nil {
return nil, err
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return nil, myerr.WrapErr(err)
}
svips, err := rpc.MGetUserSvip(model, userIds)
if err != nil {
return nil, myerr.WrapErr(err)
}
headwearMap, err := headwear_cv.BatchGetCvHeadwears(userIds)
if err != nil {
return nil, err
}
medals, err := user_m.BatchGetUserMedalMerge(model.Log, mysql.Db, userIds)
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(userIds)
if err != nil {
return nil, err
}
model.Log.Infof("getUserDetails: %+v", rooms)
groupPowers, err := groupPower_m.GetGroupPowerMap(mysql.Db, userIds)
if err != nil {
return nil, err
}
gpIds := make([]uint64, 0)
for _, i := range groupPowers {
gpIds = append(gpIds, i)
}
powerNames, err := groupPower_m.GetGroupPowerNames(mysql.Db, gpIds)
if err != nil {
return nil, err
}
groupPowerNames := make(map[mysql.ID]string, 0)
for i, g := range groupPowers {
groupPowerNames[i] = powerNames[g]
}
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)
if err != nil {
return nil, err
}
nobles, err := noble_m.BatchGetActiveNoble(mysql.Db, userIds)
if err != nil {
return nil, err
}
//判断是不是工会
userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
if err != nil {
return nil, err
}
superManagerMap, err := user_m.GetSuperManagerMap(userIds)
if err != nil {
return nil, err
}
cvUserDetails := []*CvUserDetail{}
for i := 0; i < len(users); i++ {
var headwear *headwear_cv.CvHeadwear = nil
if headwearTemp, flag := headwearMap[users[i].ID]; flag {
headwear = &headwearTemp
}
ride := property_cv.CvProperty{
Id: properties[rides[users[i].ID]].ID,
PicUrl: properties[rides[users[i].ID]].PicUrl,
EffectUrl: properties[rides[users[i].ID]].EffectUrl,
}
cvUserDetail, err := userToDetail(users[i], myUserId, userTradeUnion, likeMap, likeMeMap, rels,
vips[users[i].ID] != nil, vips[users[i].ID], svips[users[i].ID], headwear, ride,
wealthGradeMap, charmGradeMap, activeGradeMap, medals, medalInfo, rooms, groupPowers, groupPowerNames, nobles, superManagerMap)
if err != nil {
return nil, err
}
cvUserDetail.CurrentRoom, err = group_m.ToTxGroupId(model, cvUserDetail.CurrentRoom)
if err != nil {
return nil, err
}
cvUserDetails = append(cvUserDetails, cvUserDetail)
}
return cvUserDetails, nil
}
//转换
func userToDetail(user *user_m.User, myUserId mysql.ID, userTradeUnion *user_m.UserTradeUnion, likeMap map[mysql.ID]bool,
likeMeMap map[mysql.ID]bool, hvMap map[mysql.ID]Relation, isVip bool, vipExpireTime *int64, svip rpc.CvSvip, headwear *headwear_cv.CvHeadwear, ride property_cv.CvProperty,
wealthGradeMap map[mysql.ID]uint32, charmGradeMap map[mysql.ID]uint32, actityGradeMap map[mysql.ID]uint32,
medals map[uint64][]uint32, medalInfo map[uint64][]medal_cv.CvMedal, rooms map[mysql.ID]string,
powers map[mysql.ID]uint64, powerNames map[mysql.ID]string, nobles map[mysql.ID]noble_m.UserNoble, superManagerMap map[uint64]bool) (*CvUserDetail, error) {
cvUserDetail := &CvUserDetail{
CvUserBase: CvUserBase{
Id: &user.ID,
Avatar: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
DefaultAvatar: &user.DefaultAvatar,
ExternalId: StrToString(&user.ExternalId),
Nick: StrNil(IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick)),
Description: StrNil(user.Description),
Sex: TypeToUint8((*mysql.Type)(&user.Sex)),
Country: StrNil(user.Country),
CountryIcon: StrNil(user.CountryIcon),
Code: StrToString(&user.Code),
IsPrettyCode: user.IsPrettyCode(),
IsVip: isVip,
IsOfficialStaff: superManagerMap[user.ID],
VipExpireTime: vipExpireTime,
Svip: svip,
Medals: IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals[user.ID]),
MedalInfo: IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo[user.ID]),
Headwear: IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, headwear),
Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, ride),
},
IsPush: TypeToUint8((*mysql.Type)(&user.IsPush)),
}
//本人,计算,喜欢统计,钻石数量
if user.ID == myUserId {
cvUserDetail.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday)
//喜欢统计
var userCount user_m.UserCount
err := mysql.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_cv.GetDiamond(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
}
//喜欢
flag, ok := likeMap[user.ID]
if ok {
cvUserDetail.IsLike = &flag
} else {
flag := false
cvUserDetail.IsLike = &flag
}
//是否喜欢我
likeMeFlag, ok := likeMeMap[user.ID]
if ok {
cvUserDetail.IsLikeMe = &likeMeFlag
} else {
islikeMe := false
cvUserDetail.IsLikeMe = &islikeMe
}
// 永恒之心的值
hv, ok := hvMap[user.ID]
if ok {
cvUserDetail.HeartValue = hv.HeartValue
cvUserDetail.HeartValueMax = hv.HeartValueMax
cvUserDetail.MeetDays = hv.MeetDays
} else {
cvUserDetail.HeartValueMax = 0
}
//财富等级
wGroup, ok := wealthGradeMap[user.ID]
if ok {
cvUserDetail.WealthUserGrade = wGroup
} else {
cvUserDetail.WealthUserGrade = 0
}
//魅力等级
cGroup, ok := charmGradeMap[user.ID]
if ok {
cvUserDetail.CharmUserGrade = cGroup
} else {
cvUserDetail.CharmUserGrade = 0
}
//活跃等级
aGroup, ok := actityGradeMap[user.ID]
if ok {
cvUserDetail.ActivityUserGrade = aGroup
} else {
cvUserDetail.ActivityUserGrade = 0
}
cvUserDetail.CurrentRoom = rooms[user.ID]
cvUserDetail.MyGroupPower = powers[user.ID]
cvUserDetail.MyGroupPowerName = powerNames[user.ID]
if n, ok := nobles[user.ID]; ok && n.Level > 0 {
cvUserDetail.Noble = noble_cv.CvNoble{
Level: n.Level,
EndTime: n.EndTime.Unix(),
}
}
return cvUserDetail, nil
}
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 GetUserDetail(model *domain.Model, userId mysql.ID, myUserId mysql.ID) (*CvUserDetail, error) {
model.Log.Infof("GetUserDetail %d begin", userId)
var user user_m.User
var err error
if err = mysql.Db.First(&user, userId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//统计喜欢
var likeN int64
if err := mysql.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 := mysql.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]Relation, 1)
rel[userId], _ = GetRelation(myUserId, userId)
var wealthUserScore user_m.MatchWealthUserScore
if err := mysql.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 := mysql.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 := mysql.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([]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] = ""
}
}
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}
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)
properties, err := property_cv.GetPropertyAll(mysql.Db)
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(model2.UserPhoneInfo)
var thirdList []int8
if userId == myUserId {
thirdList = make([]int8, 0, 5)
// 手机绑定信息
bindInfo, err := dao.UserBindInfoDb.GetByUserId(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 := dao.UserOauthDb.GetByUserId(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 *CVCountryManager
if countryManager != nil {
cvCountryManager = &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],
noble, superManagerMap[userId], myGroups, phoneInfo, thirdList, cvCountryManager)
}
package group_c
import (
"context"
"git.hilo.cn/hilo-common/resource/redisCli"
"hilo-group/_const/redis_key"
"strings"
"time"
)
func GetGroupMemberCount(groupId string) (int, error) {
key := redis_key.GetGroupMemCountKey(groupId)
return redisCli.RedisClient.Get(context.Background(), key).Int()
}
func SetGroupMemberCount(groupId string, count uint, ttl time.Duration) error {
key := redis_key.GetGroupMemCountKey(groupId)
return redisCli.RedisClient.Set(context.Background(), key, count, ttl).Err()
}
func ClearGroupMemberCount(groupId string) error {
key := redis_key.GetGroupMemCountKey(groupId)
return redisCli.RedisClient.Del(context.Background(), key).Err()
}
func getGroupMemberKey(groupId string) string {
return strings.Replace(redis_key.GroupMemberPrefix, "{groupId}", groupId, -1)
}
func getGroupConsumeKey(groupId string) string {
return strings.Replace(redis_key.GroupConsumePrefix, "{groupId}", groupId, -1)
}
func GetGroupMember(groupId string) ([]string, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SMembers(context.Background(), key).Result()
}
func GetGroupMemberCard(groupId string) (int64, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SCard(context.Background(), key).Result()
}
func GetGroupMemberAsMap(groupId string) (map[string]struct{}, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SMembersMap(context.Background(), key).Result()
}
func SetExists(groupId string) (int64, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.Exists(context.Background(), key).Result()
}
func AddGroupMember(groupId string, extIds []string) (int64, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SAdd(context.Background(), key, extIds).Result()
}
func RemoveGroupMember(groupId string, externalId string) (int64, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SRem(context.Background(), key, externalId).Result()
}
func SetGroupMemberTTL(groupId string, ttl time.Duration) (bool, error) {
key := getGroupMemberKey(groupId)
return redisCli.RedisClient.Expire(context.Background(), key, ttl).Result()
}
func GetGroupConsume(groupId string) (uint64, error) {
key := getGroupConsumeKey(groupId)
return redisCli.RedisClient.Get(context.Background(), key).Uint64()
}
func SetGroupConsume(groupId string, consume uint64, ttl time.Duration) error {
key := getGroupConsumeKey(groupId)
return redisCli.RedisClient.Set(context.Background(), key, consume, ttl).Err()
}
func ClearGroupConsume(groupId string) error {
key := getGroupConsumeKey(groupId)
return redisCli.RedisClient.Del(context.Background(), key).Err()
}
package res_c
import (
"context"
"git.hilo.cn/hilo-common/domain"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/res_m"
"time"
)
func GetCountryIconMap(model *domain.Model) (map[string]string, error) {
m, err := GetAllCountryIcon(model)
if err != nil || len(m) <= 0 {
m, err = res_m.GetAllCountries(model)
if err != nil {
return nil, err
}
if len(m) <= 0 {
return map[string]string{}, nil
}
SaveAllCountryIcon(model, m)
}
return m, nil
}
func GetAllCountryIcon(model *domain.Model) (map[string]string, error) {
key := redis_key.GetCountryIconKey()
return model.Redis.HGetAll(context.Background(), key).Result()
}
func SaveAllCountryIcon(model *domain.Model, icons map[string]string) (int64, error) {
key := redis_key.GetCountryIconKey()
ret, err := model.Redis.HSet(context.Background(), key, icons).Result()
if err == nil {
model.Redis.Expire(context.Background(), key, time.Minute*10)
}
return ret, err
}
package room_c
import (
"context"
"errors"
"fmt"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/redisCli"
redis2 "github.com/go-redis/redis/v8"
"hilo-group/_const/redis_key"
"strconv"
"time"
)
func ProcessUserRoomVisit(userId uint64, groupId string) error {
key := redis_key.GetUserEnterRoomKey(userId)
now := time.Now()
ret, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{
Score: float64(now.Unix()),
Member: groupId,
}).Result()
if err != nil {
return err
}
mylogrus.MyLog.Infof("ProcessUserRoomVisit, ZADD %s, return %d", key, ret)
return nil
}
// 查询用户访问过的房间及其时间
func GetUserRoomVisit(userId uint64) (map[string]int64, error) {
key := redis_key.GetUserEnterRoomKey(userId)
ret, err := redisCli.GetRedis().ZRangeWithScores(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, err
}
mylogrus.MyLog.Infof("GetUserRoomVisit, ZRangeWithScores %s, return %v", key, ret)
result := make(map[string]int64, 0)
for _, i := range ret {
result[i.Member.(string)] = int64(i.Score)
}
return result, nil
}
// 批量获取房间访问人数
func MGetRoomVisitCount(groupIds []string) (map[string]string, error) {
key := redis_key.GetPrefixRoomVisitCount()
visit := make(map[string]string)
if len(groupIds) <= 0 {
return visit, nil
}
res, err := redisCli.GetRedis().HMGet(context.Background(), key, groupIds...).Result()
if err != nil {
return visit, err
}
if len(res) != len(groupIds) {
return visit, errors.New(fmt.Sprintf("MGetRoomVisitCount fail,miss match len,%v-%v", len(res), len(groupIds)))
}
for i, groupId := range groupIds {
if cnt, ok := res[i].(string); ok {
visit[groupId] = cnt
}
}
return visit, nil
}
func GetSetRoomVisitCount(groupId string) (int64, error) {
key := redis_key.GetPrefixGroupInUserDuration(groupId)
vc, err := redisCli.GetRedis().ZCard(context.Background(), key).Result()
// 查到合法值后,更新二级缓存
if err == nil && vc >= 0 {
ret, err := saveRoomVisitCount(groupId, vc)
mylogrus.MyLog.Infof("saveRoomVisitCount %s, ret = %d, err: %v", groupId, ret, err)
}
return vc, err
}
func saveRoomVisitCount(groupId string, count int64) (int64, error) {
key := redis_key.GetPrefixRoomVisitCount()
return redisCli.GetRedis().HSet(context.Background(), key, groupId, strconv.FormatInt(count, 10)).Result()
}
package bean_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/enum/bean_e"
)
//豆子账号
type BeanAccount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
BeanNum mysql.Num
Status bean_e.StatusAccount
GoldNum mysql.Num
//
addReduce mysql.AddReduce `gorm:"-"`
updateNum mysql.Num `gorm:"-"`
giftType mysql.Type `gorm:"-"`
}
package common
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/utils"
"hilo-group/_const/redis_key"
"hilo-group/myerr"
"time"
)
func GetUserMedalMergeCache(userId mysql.ID) ([]uint32, error) {
bData, err := GetCache(redis_key.GetUserMedalMerge(userId))
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 SetUserMedalMergeCache(userId mysql.ID, data []uint32) error {
err := SetCache(redis_key.GetUserMedalMerge(userId), data, time.Hour*2)
if err != nil {
mylogrus.MyLog.Errorf("SetUserMedalMerge err:%s", err)
return myerr.WrapErr(err)
}
return nil
}
// 删除勋章缓存, 延迟删除
func DelUserMedalMergeCacheDelay(userId mysql.ID) {
go func() {
defer utils.CheckGoPanic()
time.Sleep(time.Second * 5)
DelUserMedalMergeCache(userId)
}()
}
func DelUserMedalMergeCache(userId mysql.ID) error {
err := DelCache(redis_key.GetUserMedalMerge(userId))
if err != nil {
mylogrus.MyLog.Errorf("DetUserMedalMerge err:%s, userId:%v", err, userId)
return myerr.WrapErr(err)
}
return nil
}
func DelCache(key string) error {
err := redisCli.GetRedis().Del(context.Background(), key).Err()
if err != nil {
mylogrus.MyLog.Errorf("DelCache key:%s, err:%s", key, err)
return err
}
return nil
}
func GetCache(key string) ([]byte, error) {
data, err := redisCli.GetRedis().Get(context.Background(), key).Bytes()
if err != 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
}
package count_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type VideoChatTimeTotal struct {
UserId mysql.ID
VideoSeconds mysql.Num
}
// 增加视频总时长
func AddVideoChatTimeTotal(model *domain.Model, userId mysql.ID, videoSeconds mysql.Num) error {
var videoChatTimeTotal VideoChatTimeTotal
if err := model.Db.WithContext(model).Where("user_id = ?", userId).First(&videoChatTimeTotal).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("AddVideoChatTimeTotal fail:%v", err)
return err
}
// gorm.ErrRecordNotFound
videoChatTimeTotal.UserId, videoChatTimeTotal.VideoSeconds = userId, videoSeconds
if err = model.Db.WithContext(model).Create(&videoChatTimeTotal).Error; err != nil {
model.Log.Errorf("AddVideoChatTimeTotal create fail,data:%v,err:%v", videoChatTimeTotal, err)
// 高并发写,走下面的update
} else {
return nil
}
}
// update video seconds
if err := model.Db.WithContext(model).Model(VideoChatTimeTotal{}).Where("user_id = ?", userId).
UpdateColumn("video_seconds", gorm.Expr("video_seconds + ?", videoSeconds)).Error; err != nil {
model.Log.Errorf("AddVideoChatTimeTotal update fail:%v", err)
return err
}
return nil
}
// 获取视频总时长
func GetVideoChatTimeTotal(model *domain.Model, userId mysql.ID) (mysql.Num, error) {
var videoChatTimeTotal VideoChatTimeTotal
if err := model.Db.WithContext(model).Model(VideoChatTimeTotal{}).Where("user_id = ?", userId).First(&videoChatTimeTotal).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("GetVideoChatTimeTotal fail:%v", err.Error())
return 0, err
}
}
return videoChatTimeTotal.VideoSeconds, nil
}
\ No newline at end of file
package diamond_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/enum/diamond_e"
)
type DiamondAccount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondNum mysql.Num
PinkDiamondNum mysql.Num
Status diamond_e.StatusAccount
}
//账号详情
type DiamondAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
// 粉钻详情
type DiamondPinkAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
package fruit_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/fruitMachine_e"
"hilo-group/myerr"
)
type FruitMachinePlayer struct {
mysql.Entity
Date string
Round uint
UserId uint64
FruitNum uint
Award uint
}
func (fmp *FruitMachinePlayer) Create(db *gorm.DB) (int64, error) {
result := db.Clauses(clause.OnConflict{DoNothing: true}).
Create(fmp)
return result.RowsAffected, result.Error
}
func (fmp *FruitMachinePlayer) InsertUpdateFruitNum(db *gorm.DB) (int64, error) {
result := db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"fruit_num": gorm.Expr("fruit_num + IF(fruit_num>=?, 0, ?)", fruitMachine_e.MaxFruitStakeCount, fmp.FruitNum)}),
}).Create(fmp)
return result.RowsAffected, result.Error
}
func (fmp *FruitMachinePlayer) GetWinners(db *gorm.DB) ([]FruitMachinePlayer, error) {
result := make([]FruitMachinePlayer, 0)
if err := db.Where(fmp).Where("award > 0").Order("award DESC").Find(&result).Error; err != nil {
return nil, err
}
return result, nil
}
func (fmp *FruitMachinePlayer) UpdateAward(db *gorm.DB, award uint) (int64, error) {
result := db.Model(&FruitMachinePlayer{}).Where(fmp).Update("award", award)
return result.RowsAffected, result.Error
}
func (fmp *FruitMachinePlayer) Find(db *gorm.DB) ([]FruitMachinePlayer, error) {
rows := make([]FruitMachinePlayer, 0)
if err := db.Where(fmp).Order("`date` DESC, round DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func SumAward(db *gorm.DB, beginDate, endDate string) (map[uint64]uint, error) {
type sum struct {
UserId uint64
S uint
}
rows := make([]sum, 0)
if err := db.Model(&FruitMachinePlayer{}).Select("user_id,SUM(award) AS s").Where("date BETWEEN ? AND ?", beginDate, endDate).
Group("user_id").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]uint, 0)
for _, i := range rows {
result[i.UserId] = i.S
}
return result, nil
}
func SumAwardAll(db *gorm.DB, userId uint64) (uint64, error) {
type summary struct {
Sum uint64
}
results := []summary{}
err := db.Model(&FruitMachinePlayer{}).
Select("SUM(award) AS sum").
Where(&FruitMachinePlayer{
UserId: userId,
}).Find(&results).Error
if err != nil {
return 0, err
}
if len(results) == 0 {
return 0, nil
}
return results[0].Sum, err
}
func MaxAward(db *gorm.DB, userId uint64) (uint, error) {
fruitMachinePlayers := []FruitMachinePlayer{}
if err := db.Model(&FruitMachinePlayer{}).Where(&FruitMachinePlayer{
UserId: userId,
}).Order("award desc").Find(&fruitMachinePlayers).Error; err != nil {
return 0, myerr.WrapErr(err)
}
if len(fruitMachinePlayers) == 0 {
return 0, nil
}
return fruitMachinePlayers[0].Award, nil
}
type RangeSum struct {
UserId uint64
Diamond uint32
}
func SumAwardByRange(db *gorm.DB, beginDate, endDate string) ([]RangeSum, error) {
rows := make([]RangeSum, 0)
if err := db.Model(&FruitMachinePlayer{}).Select("user_id, SUM(award) AS diamond").
Where("date BETWEEN ? AND ?", beginDate, endDate).
Group("user_id").Having("diamond > 0").Order("diamond DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func SumUserAward(db *gorm.DB, userId uint64, beginDate, endDate string) (uint32, error) {
type sum struct {
UserId uint64
S uint32
}
rows := make([]sum, 0)
if err := db.Model(&FruitMachinePlayer{}).Select("user_id,SUM(award) AS s").
Where("user_id = ? AND date BETWEEN ? AND ?", userId, beginDate, endDate).
Group("user_id").Find(&rows).Error; err != nil {
return 0, err
}
if len(rows) <= 0 {
return 0, nil
}
return rows[0].S, nil
}
package game_m
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
"hilo-group/_const/enum/game_e"
"time"
)
type GameInfo struct {
Id uint64 `json:"id"`
MgId string `json:"mg_id"`
GameType game_e.GameType `json:"game_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:"game_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 GameConfig struct {
Ludo *GameConfigDiamond `json:"ludo"`
Uno *GameConfigDiamond `json:"uno"`
}
type GameConfigDiamond struct {
Diamond []uint32 `json:"diamond"`
}
func GetGameInfo(model *domain.Model, gameType game_e.GameType, gameId uint64, txGroupId, roundId string, battleEndAt, status int64) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
if gameType != 0 {
db = db.Where("game_type = ?", gameType)
}
if gameId != 0 {
db = db.Where("id = ?", gameId)
}
if txGroupId != "" {
db = db.Where("tx_group_id = ?", txGroupId)
}
if roundId != "" {
db = db.Where("game_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
}
// 获取所有未结束的游戏
// return map $txGroupId->[]GameTypes
func GetNotEndGamesMap(model *domain.Model) map[string][]game_e.GameType {
var res = make(map[string][]game_e.GameType)
var games []GameInfo
if err := model.Db.Model(GameInfo{}).Where("status in (0,1)").Find(&games).Error; err != nil {
model.Log.Errorf("GetNotEndGamesMap fail:%v", err)
return res
}
for _, game := range games {
res[game.TxGroupId] = []game_e.GameType{game.GameType}
}
return res
}
package gift_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/gift_e"
"hilo-group/domain/model/res_m"
"hilo-group/myerr"
"time"
)
/**
* 礼物操作
**/
type GiftOperate struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResGiftId mysql.ID
GiftN mysql.Num
SendUserId mysql.ID
ReceiveUserId mysql.ID
SendUserDiamond mysql.Num
ReceiveUserDiamond mysql.Num
ReceiveUserBean mysql.Num
SceneType gift_e.GiftOperateSceneType
SceneUid mysql.Str
}
// 用户收取礼物分类统计(for 礼物墙)
type GiftCountUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
ResGiftId mysql.ID
Num mysql.Num
addNum mysql.Num `gorm:"-"`
}
/**
* 送礼物
**/
func SendGift(model *domain.Model, giftId mysql.ID, giftN mysql.Num, sendUserId mysql.ID, receiveUserId mysql.ID, sceneType gift_e.GiftOperateSceneType, sceneUid mysql.Str) (*GiftOperate, *res_m.ResGift, error) {
resGift, err := res_m.GetGiftWithValid(model, giftId)
if err != nil {
return nil, nil, err
}
return &GiftOperate{
Model: model,
ResGiftId: giftId,
GiftN: giftN,
SendUserId: sendUserId,
ReceiveUserId: receiveUserId,
SendUserDiamond: resGift.DiamondNum * giftN,
ReceiveUserDiamond: resGift.ReceiveDiamondNum * giftN,
ReceiveUserBean: resGift.BeanNum * giftN,
SceneType: sceneType,
SceneUid: sceneUid,
}, resGift, nil
}
func GetCountGiftOperateByDay(model *domain.Model, userId uint64, beginTime, endTime time.Time) (int64, error) {
var n int64 = 0
if err := model.Db.Model(&GiftOperate{}).Where(&GiftOperate{
SendUserId: userId,
}).Where("created_time >= ? and created_time <= ?", beginTime, endTime).Distinct("Receive_User_Id").Count(&n).Error; err != nil {
return 0, err
}
return n, nil
}
func GetGiftSummaryByDay(userId uint64, sceneType gift_e.GiftOperateSceneType, beginTime, endTime time.Time) (map[string]uint64, error) {
c := GiftOperate{ReceiveUserId: userId, SceneType: sceneType}
type summary struct {
Date string
Sum uint64
}
records := make([]summary, 0)
err := mysql.Db.Model(&GiftOperate{}).
Select("DATE_FORMAT(created_time, '%Y-%m-%d') AS date, SUM(receive_user_bean) AS sum").
Where(c).Where("created_time BETWEEN ? AND ?", beginTime, endTime).
Group("date").Find(&records).Error
if err != nil {
return nil, err
}
result := make(map[string]uint64, len(records))
for _, i := range records {
result[i.Date] = i.Sum
}
return result, err
}
func GetGiftAllSummaryByDay(userId uint64, beginTime, endTime time.Time) (map[string]uint64, error) {
c := GiftOperate{ReceiveUserId: userId}
type summary struct {
Date string
Sum uint64
}
records := make([]summary, 0)
err := mysql.Db.Model(&GiftOperate{}).
Select("DATE_FORMAT(created_time, '%Y-%m-%d') AS date, SUM(receive_user_bean) AS sum").
Where(c).Where("created_time BETWEEN ? AND ?", beginTime, endTime).
Group("date").Find(&records).Error
if err != nil {
return nil, err
}
result := make(map[string]uint64, len(records))
for _, i := range records {
result[i.Date] = i.Sum
}
return result, err
}
func (g *GiftOperate) GetConsumeByRange(beginTime, endTime time.Time) (uint32, uint64, error) {
type summary struct {
C uint32
Consume uint64
}
rows := make([]summary, 0)
err := g.Db.Model(g).
Select("COUNT(DISTINCT(send_user_id)) AS c, SUM(send_user_diamond) AS Consume").
Where(g).Where("created_time BETWEEN ? AND ?", beginTime, endTime).
Find(&rows).Error
if err != nil {
return 0, 0, err
}
if len(rows) <= 0 {
return 0, 0, nil
}
return rows[0].C, rows[0].Consume, nil
}
type SceneConsumeSummary struct {
SceneUid string
C uint32
Consume uint64
}
func (g *GiftOperate) BatchGetConsumeByRange(beginTime, endTime time.Time) ([]SceneConsumeSummary, error) {
rows := make([]SceneConsumeSummary, 0)
err := g.Db.Model(g).
Select("scene_uid, COUNT(DISTINCT(send_user_id)) AS c, SUM(send_user_diamond) AS Consume").
Where(g).Where("created_time BETWEEN ? AND ?", beginTime, endTime).
Group("scene_uid").Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func SumSendGift(model *domain.Model, sendUserId mysql.ID, giftId mysql.ID) (uint32, error) {
type Result struct {
N uint32
}
sum := Result{}
if err := model.Db.Raw("SELECT SUM(o.gift_n) as n from gift_operate o where o.send_user_id = ? and o.res_gift_id = ?", sendUserId, giftId).Scan(&sum).Error; err != nil {
return 0, myerr.WrapErr(err)
} else {
return sum.N, nil
}
}
type GiftPrivateRecord struct {
mysql.Entity
ResGiftId mysql.ID
GiftN mysql.Num
DiamondNum mysql.Num
SendUserId mysql.ID
ReceiveUserId mysql.ID
RefId mysql.ID //其实就是diamondSendAccountDetailId
OriginType gift_e.GiftPrivateRecordType //来源类型
OriginId mysql.ID //来源ID
}
func (gpr *GiftPrivateRecord) Create(db *gorm.DB) error {
return db.Create(gpr).Error
}
func (gpr *GiftPrivateRecord) Find(db *gorm.DB) ([]GiftPrivateRecord, error) {
rows := make([]GiftPrivateRecord, 0)
if err := db.Where(gpr).Order("created_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (gpr *GiftPrivateRecord) Remove(db *gorm.DB) (int64, error) {
result := db.Delete(gpr)
return result.RowsAffected, result.Error
}
func GetGiftOperate(resGift *res_m.ResGift, giftId mysql.ID, giftN mysql.Num, sendUserId mysql.ID,
receiveUserId mysql.ID, sceneType gift_e.GiftOperateSceneType, sceneUid mysql.Str) *GiftOperate {
return &GiftOperate{
ResGiftId: giftId,
GiftN: giftN,
SendUserId: sendUserId,
ReceiveUserId: receiveUserId,
SendUserDiamond: resGift.DiamondNum * giftN,
ReceiveUserDiamond: resGift.ReceiveDiamondNum * giftN,
ReceiveUserBean: resGift.BeanNum * giftN,
SceneType: sceneType,
SceneUid: sceneUid,
}
}
package groupPower_m
import (
"context"
"encoding/json"
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/groupPower_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/group_m"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"runtime/debug"
"strconv"
"time"
)
type GroupPower struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
Name mysql.Str
Status groupPower_e.GroupPowerStatus
}
type GroupPowerUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupPowerId mysql.ID
UserId mysql.ID
Role groupPower_e.GroupPowerUserRole
}
func (gpu *GroupPowerUser) Get(db *gorm.DB) ([]GroupPowerUser, error) {
rows := make([]GroupPowerUser, 0)
err := db.Where(gpu).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func GetPowerOwner(db *gorm.DB, powerId uint64) (uint64, error) {
gpu := GroupPowerUser{GroupPowerId: powerId, Role: groupPower_e.GroupPowerUserRoleMgr}
records, err := gpu.Get(db)
if err != nil {
return 0, err
}
if len(records) != 1 {
return 0, bizerr.GroupPowerNoOwner
}
return records[0].UserId, nil
}
func GetMyPowerId(db *gorm.DB, userId uint64) (uint64, error) {
gpu := GroupPowerUser{UserId: userId, Role: groupPower_e.GroupPowerUserRoleMgr}
records, err := gpu.Get(db)
if err != nil {
return 0, err
}
if len(records) > 0 {
return records[0].GroupPowerId, nil
}
return 0, nil
}
func (gpu *GroupPowerUser) GetCount(db *gorm.DB) (uint, error) {
var count int64 = 0
err := db.Model(&GroupPowerUser{}).Where(gpu).Count(&count).Error
if err != nil {
return 0, err
}
return uint(count), nil
}
type GroupPowerUserLog struct {
mysql.Entity
GroupPowerId mysql.ID
UserId mysql.ID
OperateType groupPower_e.GroupPowerUserLogType
Remark mysql.Str
}
//记录日志
func addGroupPowerUserLog(model *domain.Model, groupPowerId mysql.ID, userId mysql.ID, operateType groupPower_e.GroupPowerUserLogType, remark string) error {
if err := model.Db.Create(&GroupPowerUserLog{
GroupPowerId: groupPowerId,
UserId: userId,
OperateType: operateType,
Remark: remark,
}).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GetGroupPowerUserLog(db *gorm.DB, groupPowerId mysql.ID, beginTime time.Time) ([]GroupPowerUserLog, error) {
rows := make([]GroupPowerUserLog, 0)
gpu := GroupPowerUserLog{GroupPowerId: groupPowerId}
if err := db.Where(gpu).Where("created_time BETWEEN ? AND NOW()", beginTime).Order("id DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
type GroupPowerDiamondLog struct {
mysql.Entity
GroupPowerId mysql.ID
SendUserId mysql.ID
SendGroupId mysql.Str
ReceiveUserId mysql.ID
DiamondNum mysql.Num
GiftId mysql.ID
GiftNum mysql.Num
GiftOperateId mysql.ID
Type groupPower_e.GroupPowerDiamondLogType
}
func (*GroupPowerDiamondLog) TableName() string {
month := time.Now().Format("200601")
return fmt.Sprintf("group_power_diamond_log_%s", month)
}
func addGroupPowerDiamondLog(model *domain.Model, groupPowerId mysql.ID, sendUserId mysql.ID, sendGroupId mysql.Str, receiveUserId mysql.ID, diamondNum mysql.Num, giftId mysql.ID, giftNum mysql.Num, giftOperateId mysql.ID, t groupPower_e.GroupPowerDiamondLogType) error {
if err := model.Db.Table((&GroupPowerDiamondLog{}).TableName()).Create(&GroupPowerDiamondLog{
GroupPowerId: groupPowerId,
SendUserId: sendUserId,
SendGroupId: sendGroupId,
ReceiveUserId: receiveUserId,
DiamondNum: diamondNum,
GiftId: giftId,
GiftNum: giftNum,
GiftOperateId: giftOperateId,
Type: t,
}).Error; err != nil {
return myerr.WrapErr(err)
}
go func() {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
model.Log.Errorf("GroupPowerDiamondLog Persistent SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
//增加到缓存,不要处理错误,接受缓存失败
now := time.Now()
nowTime, err := time.ParseInLocation(utils.DATE_FORMAT, now.Format(utils.DATE_FORMAT), time.Local)
if err != nil {
model.Log.Infof("addGroupPowerDiamondLog ZIncrBy err:%v", err)
}
beginDate := utils.GetMonday(nowTime)
key := redis_key.GetGroupPowerDiamondLogWeek(beginDate.Format(utils.COMPACT_DATE_FORMAT))
if err := redisCli.GetRedis().ZIncrBy(context.Background(), key, float64(diamondNum), strconv.FormatUint(groupPowerId, 10)).Err(); err != nil {
model.Log.Infof("addGroupPowerDiamondLog ZIncrBy err:%v", err)
}
if ttl, err := redisCli.GetRedis().TTL(context.Background(), key).Result(); err != nil {
model.Log.Errorf("addGroupPowerDiamondLog ZIncrBy TTL err:%v, key:%v", err, key)
} else {
if ttl < 0 {
//延长到30天,避免数据丢失
redisCli.GetRedis().ExpireAt(context.Background(), key, time.Now().AddDate(0, 0, 30))
}
}
}()
return nil
}
type GroupPowerWeekDiamond struct {
Week string
PowerId mysql.ID
GroupId mysql.Str
Diamond uint64
}
func (gpwd *GroupPowerWeekDiamond) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"diamond": gorm.Expr("diamond + ?", gpwd.Diamond)}),
}).Create(gpwd).Error
}
func GetPowerWeekDiamond(db *gorm.DB, week string, powerId mysql.ID) (uint32, error) {
gpwd := GroupPowerWeekDiamond{Week: week, PowerId: powerId}
type summary struct {
Sum uint32
}
row := summary{}
if err := db.Model(&GroupPowerWeekDiamond{}).
Select("SUM(diamond) AS sum").Where(&gpwd).First(&row).Error; err != nil {
return 0, err
}
return row.Sum, nil
}
func GetAllPowerWeekDiamond(db *gorm.DB, week string) (map[uint64]uint32, error) {
gpwd := GroupPowerWeekDiamond{Week: week}
type summary struct {
PowerId uint64
Sum uint32
}
rows := make([]summary, 0)
if err := db.Model(&GroupPowerWeekDiamond{}).
Select("power_id, SUM(diamond) AS sum").Where(&gpwd).Group("power_id").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]uint32, 0)
for _, i := range rows {
result[i.PowerId] = i.Sum
}
return result, nil
}
type PowerSupportAward struct {
mysql.Entity
Week string
PowerId mysql.ID
Diamond uint32
Level string
Owner mysql.ID
OwnerSalary uint32
Assistant_1 mysql.ID
Assistant_2 mysql.ID
Assistant_3 mysql.ID
Assistant_Salary uint32
}
func (psa *PowerSupportAward) Create(db *gorm.DB) (int64, error) {
result := db.Clauses(clause.OnConflict{DoNothing: true}).
Create(psa)
return result.RowsAffected, result.Error
}
func (psa *PowerSupportAward) Find(db *gorm.DB) (*PowerSupportAward, error) {
rows := make([]PowerSupportAward, 0)
if err := db.Where(psa).Find(&rows).Error; err != nil {
return nil, err
}
if len(rows) <= 0 {
return nil, nil
}
return &rows[0], nil
}
func (psa *PowerSupportAward) FindAll(db *gorm.DB) ([]PowerSupportAward, error) {
rows := make([]PowerSupportAward, 0)
if err := db.Where(psa).Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func GetGroupPowerByUserId(model *domain.Model, userId uint64) (*GroupPower, error) {
if groupPowerUser, err := GetGroupPowerUserOrNil(model, userId); err != nil {
return nil, err
} else if groupPowerUser == nil {
return nil, nil
} else {
return GetGroupPowerOrErr(model, groupPowerUser.GroupPowerId)
}
}
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
}
func InitGroupPower(model *domain.Model, groupUuid string, name string, owerUserId mysql.ID) (*GroupPower, *GroupPowerUser, error) {
//检查改用户是否已经加入了别的势力
/* var n int64
if err := model.Db.Model(&GroupPowerUser{}).Where(&GroupPowerUser{
UserId: owerUserId,
}).Count(&n).Error; err != nil {
return nil, nil, myerr.NewSysErrorF("用户已经加入了别的势力")
}*/
if flag, _, err := CheckGroupPowerUser(model, owerUserId); err != nil {
return nil, nil, err
} else if flag {
return nil, nil, myerr.NewSysErrorF("用户已经加入了别的势力")
}
return &GroupPower{
Model: model,
GroupUid: groupUuid,
Name: name,
Status: groupPower_e.GroupPowerUserHas,
}, &GroupPowerUser{
Model: model,
GroupPowerId: 0,
UserId: owerUserId,
Role: groupPower_e.GroupPowerUserRoleMgr,
}, 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 GetGroupPowerByGroupOrNil(model *domain.Model, groupUid string) (*GroupPower, error) {
groupPower := GroupPower{}
if err := model.Db.Where(&GroupPower{
GroupUid: groupUid,
}).First(&groupPower).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupPower.Model = model
return &groupPower, nil
}
func GetGroupPowerMap(db *gorm.DB, userIds []mysql.ID) (map[mysql.ID]uint64, error) {
rows := make([]GroupPowerUser, 0)
if len(userIds) > 0 {
if err := db.Model(&GroupPowerUser{}).Where("user_id IN ?", userIds).Find(&rows).Error; err != nil {
return nil, err
}
}
result := make(map[mysql.ID]uint64, 0)
for _, i := range rows {
result[i.UserId] = i.GroupPowerId
}
return result, nil
}
func GetGroupPowerNames(db *gorm.DB, ids []mysql.ID) (map[mysql.ID]string, error) {
type record struct {
Id mysql.ID
Name string
}
rows := make([]record, 0)
if len(ids) > 0 {
if err := db.Model(&GroupPower{}).Select("p.id, i.name").
Joins("AS p INNER JOIN group_info AS i ON p.group_uid = i.im_group_id").
Where("p.id IN ?", ids).Find(&rows).Error; err != nil {
return nil, err
}
}
result := make(map[mysql.ID]string, 0)
for _, i := range rows {
result[i.Id] = i.Name
}
return result, nil
}
type GroupPowerInfo struct {
PowerId mysql.ID
Owner mysql.ID
Name string
}
func BatchGetGroupPower(db *gorm.DB, ids []mysql.ID) (map[mysql.ID]GroupPowerInfo, error) {
rows := make([]GroupPowerInfo, 0)
if len(ids) > 0 {
if err := db.Model(&GroupPower{}).Select("p.id AS power_id, u.user_id AS owner, p.name").
Joins("AS p INNER JOIN group_power_user AS u ON p.id = u.group_power_id").
Where("p.id IN ? AND p.status = ? AND role = ?", ids, groupPower_e.GroupPowerUserHas, groupPower_e.GroupPowerUserRoleMgr).
Find(&rows).Error; err != nil {
return nil, err
}
}
result := make(map[mysql.ID]GroupPowerInfo, 0)
for _, i := range rows {
result[i.PowerId] = i
}
return result, nil
}
func GetGroupPower(model *domain.Model, id mysql.ID) (*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
}
// 判断势力是否合法
func IsGroupPowerActive(model *domain.Model, id mysql.ID) (bool, error) {
gp, err := GetGroupPower(model, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return false, nil
} else {
return false, err
}
}
if gp == nil || gp.Status != groupPower_e.GroupPowerUserHas {
return false, nil
}
return true, nil
}
func getGroupPowerUser(model *domain.Model, groupPowerId mysql.ID, userId mysql.ID) (*GroupPowerUser, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
GroupPowerId: groupPowerId,
UserId: userId,
}).First(&groupPowerUser).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupPowerUser.Model = model
return &groupPowerUser, nil
}
//false:不存在, true:存在
func CheckGroupPowerUser(model *domain.Model, userId mysql.ID) (bool, mysql.ID, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
UserId: userId,
}).First(&groupPowerUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return false, 0, nil
} else {
return false, 0, myerr.WrapErr(err)
}
}
return true, groupPowerUser.GroupPowerId, nil
}
//获取势力主
func GetGroupPowerMgr(model *domain.Model, groupPowerId mysql.ID) (mysql.ID, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
GroupPowerId: groupPowerId,
Role: groupPower_e.GroupPowerUserRoleMgr,
}).First(&groupPowerUser).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return groupPowerUser.UserId, nil
}
//运营平台让用户离开
func (groupPower *GroupPower) MgrUserLeave(userId mysql.ID) (*GroupPowerUser, error) {
//
groupPowerUser, err := getGroupPowerUser(groupPower.Model, groupPower.ID, userId)
if err != nil {
return nil, err
}
if groupPowerUser.Role == groupPower_e.GroupPowerUserRoleMgr {
return nil, bizerr.GroupPowerOwnerLeave
}
if err := addGroupPowerUserLog(groupPower.Model, groupPower.ID, userId, groupPower_e.GroupPowerUserLogTypeMgrLeave, ""); err != nil {
return nil, err
}
groupPowerUser.SetDel()
return groupPowerUser, nil
}
//正常
func (groupPower *GroupPower) MgrNormal() *GroupPower {
groupPower.Status = groupPower_e.GroupPowerUserHas
return groupPower
}
//冻结
func (groupPower *GroupPower) MgrFrozen() *GroupPower {
groupPower.Status = groupPower_e.GroupPowerUserNo
return groupPower
}
//解散。移除所有信息
func (groupPower *GroupPower) MgrDissolve() (*GroupPower, error) {
//对比查询的数量 == 删除的数量,不一致,则不能删除
if groupPower.ID == 0 {
return groupPower, myerr.NewSysErrorF("groupPower dissolve groupPowerId = 0")
}
groupPowerUsers := []GroupPowerUser{}
if err := groupPower.Db.Model(&GroupPowerUser{}).Where(&GroupPowerUser{
GroupPowerId: groupPower.ID,
}).Find(&groupPowerUsers).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if len(groupPowerUsers) == 0 {
return nil, myerr.NewSysErrorF("groupPower dissolve user.num == 0")
}
//删除groupPowerUser中信息
delN := groupPower.Db.Model(&GroupPowerUser{}).Where(&GroupPowerUser{
GroupPowerId: groupPower.ID,
}).Delete(&GroupPowerUser{
GroupPowerId: groupPower.ID,
}).RowsAffected
if int64(len(groupPowerUsers)) != delN {
return nil, myerr.NewSysErrorF("groupPower dissolve delN != selectN")
}
groupPowerUserStr, err := json.Marshal(groupPowerUsers)
if err != nil {
return nil, myerr.WrapErr(err)
}
//增加删除日志
if err := addGroupPowerUserLog(groupPower.Model, groupPower.ID, 0, groupPower_e.GroupPowerUserLogDissolve, string(groupPowerUserStr)); err != nil {
return nil, myerr.WrapErr(err)
}
//
groupPower.Status = groupPower_e.GroupPowerDissolve
groupPower.GroupUid = groupPower.GroupUid + "_" + "del" + "_" + time.Now().Format(utils.COMPACT_MONTH_FORMAT)
return groupPower, nil
}
//修改名字
func (groupPower *GroupPower) EditName(name string) *GroupPower {
groupPower.Name = name
return groupPower
}
//修改群组
func (groupPower *GroupPower) EditGroupUid(groupUid string) *GroupPower {
groupPower.GroupUid = groupUid
return groupPower
}
func (groupPower *GroupPower) EditPowerOwer(owerUserId mysql.ID) (*GroupPower, *GroupPowerUser, *GroupPowerUser, error) {
oldGroupPowerUser := GroupPowerUser{}
if err := groupPower.Db.Where(&GroupPowerUser{
GroupPowerId: groupPower.ID,
Role: groupPower_e.GroupPowerUserRoleMgr,
}).First(&oldGroupPowerUser).Error; err != nil {
return nil, nil, nil, myerr.WrapErr(err)
}
//势力主离开,
if oldGroupPowerUser.UserId == owerUserId {
//势力主没有变化,无需修改
return groupPower, nil, nil, nil
} else {
oldGroupPowerUser.Model = groupPower.Model
oldGroupPowerUser.SetDel()
if err := addGroupPowerUserLog(groupPower.Model, groupPower.ID, oldGroupPowerUser.UserId, groupPower_e.GroupPowerUserLogTypeMgrLeave, ""); err != nil {
return nil, nil, nil, err
}
}
//
return groupPower, &oldGroupPowerUser, &GroupPowerUser{
Model: groupPower.Model,
GroupPowerId: groupPower.ID,
UserId: owerUserId,
Role: groupPower_e.GroupPowerUserRoleMgr,
}, nil
}
//增加普通用户
func (groupPower *GroupPower) UserJoin(userId mysql.ID) (*GroupPowerUser, error) {
//判断是否已经加入了国家势力
if flag, groupPowerId, err := CheckGroupPowerUser(groupPower.Model, userId); err != nil {
return nil, err
} else if flag == true {
if groupPowerId == groupPower.ID {
return nil, bizerr.GroupPowerHasJoinMy
} else {
return nil, bizerr.GroupPowerHasJoinOther
}
}
if err := addGroupPowerUserLog(groupPower.Model, groupPower.ID, userId, groupPower_e.GroupPowerUserLogTypeUserJoin, ""); err != nil {
return nil, err
}
return &GroupPowerUser{
Model: groupPower.Model,
GroupPowerId: groupPower.ID,
UserId: userId,
Role: groupPower_e.GroupPowerUserRoleUser,
}, nil
}
// 离开国家势前至少要多少小时
const GROUP_POWER_LEAVE_LIMIT = 3
//用户退出国家势力
func (groupPower *GroupPower) UserLeave(userId mysql.ID) (*GroupPowerUser, time.Duration, error) {
groupPowerUser, err := getGroupPowerUser(groupPower.Model, groupPower.ID, userId)
if err != nil {
return nil, 0, err
}
if groupPowerUser.Role == groupPower_e.GroupPowerUserRoleMgr {
return nil, 0, bizerr.GroupPowerOwnerLeave
}
// 2022-02-14产品增加限制:加入势力10天内不能退出;2022-02-28:调整为15天;2022-06-20调整为3小时
now := time.Now()
endTime := groupPowerUser.CreatedTime.Add(time.Hour * GROUP_POWER_LEAVE_LIMIT)
if now.Before(endTime) {
diff := endTime.Sub(now)
return nil, diff, bizerr.GroupPowerStayTooShort
}
if err := addGroupPowerUserLog(groupPower.Model, groupPower.ID, userId, groupPower_e.GroupPowerUserLogTypeUserLeave, ""); err != nil {
return nil, 0, err
}
groupPowerUser.SetDel()
return groupPowerUser, 0, nil
}
// 查询用户加入的国家势力ID及名称(势力绑定的群组的名称)
func GetUserGroupPower(model *domain.Model, userId uint64) (uint64, string, error) {
gpu, err := GetGroupPowerUserOrNil(model, userId)
if err != nil {
return 0, "", err
}
if gpu == nil || gpu.GroupPowerId == 0 {
return 0, "", nil
}
gp, err := GetGroupPowerOrErr(model, gpu.GroupPowerId)
if err != nil {
return 0, "", err
}
powerName := ""
if gp != nil && len(gp.GroupUid) > 0 {
gi, err := group_m.GetGroupInfo(model, gp.GroupUid)
if err != nil {
return 0, "", err
}
if gi != nil {
// 只要前15个字
s := []rune(gi.Name)
if len(s) <= 15 {
powerName = string(s)
} else {
powerName = string(s[0:15])
}
}
}
return gpu.GroupPowerId, powerName, nil
}
package groupPower_m
import (
"hilo-group/domain/model"
"hilo-group/myerr"
)
func (groupPower *GroupPower) Persistent() error {
if err := model.Persistent(groupPower.Db, groupPower); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupPowerUser *GroupPowerUser) Persistent() error {
if err := model.Persistent(groupPowerUser.Db, groupPowerUser); err != nil {
return myerr.WrapErr(err)
}
return nil
}
package group_m
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/sdk/agora"
redisV8 "github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/myerr"
"strconv"
"strings"
"time"
)
//获取群组的最大消息序列
func getRediGroupMsgMaxSeqOrInit(groupUuid string) (*RediGroupMsgSeqMax, error) {
//Map结构
nStr, err := redisCli.RedisClient.HGet(context.Background(), redis_key.GetPrefixGroupMsgSeqMaxAll(), groupUuid).Result()
if err != nil {
if err == redisV8.Nil {
return &RediGroupMsgSeqMax{
Seq: 0,
GroupUuid: groupUuid,
}, nil
} else {
return nil, err
}
}
if nStr == "" {
return &RediGroupMsgSeqMax{
Seq: 0,
GroupUuid: groupUuid,
}, nil
}
seq, err := strconv.ParseUint(nStr, 0, 64)
if err != nil {
return nil, myerr.WrapErr(err)
}
return &RediGroupMsgSeqMax{
Seq: seq,
GroupUuid: groupUuid,
}, nil
}
//获取群组中某个用户的最大消息序列
func GetRedisGroupUserMsgMaxSeqOrInit(groupUuid string, externalId string) (*RedisGroupMsgSeqMaxUser, error) {
//Map结构
nStr, err := redisCli.RedisClient.HGet(context.Background(), redis_key.GetPrefixGroupMsgSeqMaxGroup(groupUuid), externalId).Result()
if err != nil {
if err == redisV8.Nil {
return &RedisGroupMsgSeqMaxUser{
GroupUuid: groupUuid,
ExternalId: externalId,
Seq: 0,
}, nil
} else {
return nil, err
}
}
seq, err := strconv.ParseUint(nStr, 0, 64)
if err != nil {
return nil, myerr.WrapErr(err)
}
return &RedisGroupMsgSeqMaxUser{
GroupUuid: groupUuid,
ExternalId: externalId,
Seq: seq,
}, nil
}
//获取群与人,如果不存在,则初始化
func GetGroupUserOrInit(model *domain.Model, groupId mysql.Str, userId mysql.ID) (*GroupUser, error) {
var groupUser GroupUser
if err := model.Db.Where(&GroupUser{
GroupId: groupId,
UserId: userId,
}).First(&groupUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &GroupUser{
Model: model,
GroupId: groupId,
UserId: userId,
MsgStatus: group_e.NormalMsgStatusGroupUser,
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupUser.Model = model
return &groupUser, nil
}
//以groupInfoId 为准,如果数据不存在,则是默认值,因此返回值的size 是同groupInfoIdds size 一致
func GetGroupUserMap(model *domain.Model, groupIds []mysql.Str, userId mysql.ID) ([]GroupUser, error) {
if len(groupIds) == 0 {
return []GroupUser{}, nil
}
groupUsers := []GroupUser{}
if err := model.Db.Where(&GroupUser{
UserId: userId,
}).Where("group_id IN (?)", groupIds).Find(&groupUsers).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupUserMap := map[mysql.Str]*GroupUser{}
for i := 0; i < len(groupUsers); i++ {
groupUserMap[groupUsers[i].GroupId] = &groupUsers[i]
}
r := []GroupUser{}
//顺序排列
for i := 0; i < len(groupIds); i++ {
if g, ok := groupUserMap[groupIds[i]]; ok {
r = append(r, *g)
} else {
r = append(r, GroupUser{
GroupId: groupIds[i],
UserId: userId,
MsgStatus: group_e.NormalMsgStatusGroupUser,
})
}
}
return r, nil
}
//获取过期用户消息
func getExpireRedisGroupUserMsgDuration() ([]*RedisGroupMsgDurationUser, error) {
//sorted set
//println(time.Now().Unix())
score := time.Now().Unix() - int64(config.GetGroupImConfig().MSG_SORT_EXPIRE)
//redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis.GetPrefixGroupMsgDurationUser(), "", strconv.FormatInt(score, 10)).Result()
zList, err := redisCli.RedisClient.ZRevRangeByScoreWithScores(context.Background(), redis_key.GetPrefixGroupMsgDurationUser(), &redisV8.ZRangeBy{
Min: "0",
Max: strconv.FormatInt(score, 10),
}).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
//
redisGroupUserMsgDurations := []*RedisGroupMsgDurationUser{}
for _, v := range zList {
groupUuidUserId := v.Member
//移除
n, err := redisCli.GetRedis().ZRem(context.Background(), redis_key.GetPrefixGroupMsgDurationUser(), groupUuidUserId).Result()
if err == nil && n > 0 {
//
strs := strings.Split(groupUuidUserId.(string), "_")
//
if err != nil {
return nil, myerr.WrapErr(err)
}
redisGroupUserMsgDurations = append(redisGroupUserMsgDurations, &RedisGroupMsgDurationUser{
GroupUuid: strs[0],
ExternalId: strs[1],
})
}
}
return redisGroupUserMsgDurations, nil
}
//获取过期用户消息
func initRedisGroupUserMsgDuration(groupUuid string, externalId string) *RedisGroupMsgDurationUser {
return &RedisGroupMsgDurationUser{
GroupUuid: groupUuid,
ExternalId: externalId,
TimeStamp: time.Now().Unix(),
}
}
func getRedisGroupMsgDurationScoreInit(groupUuid string) (*RedisGroupMsgDurationScore, error) {
return &RedisGroupMsgDurationScore{
GroupUuid: groupUuid,
AddCountUser: 0,
}, nil
}
//获取群组消息的用户数量
//func getRedisGroupMsgDurationScoreOrInit(groupUuid string) (*RedisGroupMsgDurationScore, error) {
// score, err := redisCli.RedisClient.ZScore(context.Background(), redis.GetPrefixGroupMsgDurationScore(), groupUuid).Result()
// if err != nil {
// //不存在
// if err == redisV8.Nil {
// return &RedisGroupMsgDurationScore{
// GroupUuid: groupUuid,
// AddCountUser: 0,
// }, nil
// } else {
// return nil, myerr.WrapErr(err)
// }
// }
// return &RedisGroupMsgDurationScore{
// GroupUuid: groupUuid,
// AddCountUser: int(score),
// }, nil
//}
//直接初始化
func InitGroupMsg(model *domain.Model, callbackCommand string, groupId string, t string, fromAccount string, operatorAccount string, random int, msgSeq uint64, msgTime uint64, onlineOnlyFlag uint8, msgBody string) *GroupMsg {
return &GroupMsg{
Model: model,
CallbackCommand: callbackCommand,
GroupId: groupId,
Type: t,
FromAccount: fromAccount,
OperatorAccount: operatorAccount,
Random: random,
MsgSeq: msgSeq,
MsgTime: msgTime,
MsgBody: msgBody,
}
}
//获取麦上的人
func GetAllMicUser(groupUuid string) ([]mysql.ID, error) {
var userIds []mysql.ID
for i := 1; i <= MaxMicNum; i++ {
micUserStr, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupMicUser(groupUuid, i)).Result()
if err != nil {
if err != redisV8.Nil {
return nil, myerr.WrapErr(err)
}
} else {
var micUser MicUser
if err = json.Unmarshal([]byte(micUserStr), &micUser); err != nil {
return nil, myerr.WrapErr(err)
}
userIds = append(userIds, micUser.UserId)
}
}
return userIds, nil
}
// 批量获取多个房间里麦上的人
func BatchGetAllMicUser(model *domain.Model, groupIds []string) (map[string][]mysql.ID, error) {
result := make(map[string][]mysql.ID, 0)
if len(groupIds) <= 0 {
return result, nil
}
keys := make([]string, 0)
for _, g := range groupIds {
for i := 1; i <= MaxMicNum; i++ {
keys = append(keys, redis_key.GetPrefixGroupMicUser(g, i))
}
}
mics, err := redisCli.GetRedis().MGet(context.Background(), keys...).Result()
if err != nil {
return nil, err
}
model.Log.Infof("BatchGetAllMicUser redis return size = %d, mics: %v", len(mics), mics)
if len(mics) >= len(groupIds) {
for i, g := range groupIds {
result[g] = make([]mysql.ID, 0)
for j := 1; j <= MaxMicNum; j++ {
k := i*MaxMicNum + j - 1
if mics[k] != nil {
switch mics[k].(type) {
case string:
s := mics[k].(string)
var micUser MicUser
if err = json.Unmarshal([]byte(s), &micUser); err != nil {
return nil, myerr.WrapErr(err)
}
model.Log.Debugf("BatchGetAllMicUser %s-%d return %v", g, j, micUser)
result[g] = append(result[g], micUser.UserId)
default:
model.Log.Warnf("BatchGetAllMicUser %s-%d return unknown type", g, j)
}
}
}
}
}
return result, nil
}
func GetAllMic(groupUuid string, numType group_e.GroupMicNumType) ([]Mic, []MicUser, error) {
/* n := 0
if numType == group_m.OneMicNumType {
n = 1
}else if numType == group_m.TwoMicNumType {
n = 2
}*/
n := GetMicNum(numType)
micUserMap := map[int]string{}
for i := 1; i <= n; i++ {
//fixme:使用redis mget来替代。
micUser, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupMicUser(groupUuid, i)).Result()
if err != nil {
if err != redisV8.Nil {
return nil, nil, myerr.WrapErr(err)
}
} else {
micUserMap[i] = micUser
}
}
//fixme:这里检查是否有重复的,最后的防线
micMap, err := redisCli.GetRedis().HGetAll(context.Background(), redis_key.GetPrefixGroupMic(groupUuid)).Result()
if err != nil {
if err == redisV8.Nil {
micMap = map[string]string{}
} else {
return nil, nil, myerr.WrapErr(err)
}
}
//fixme:这里检查是否有重复的,最后的防线
var mics []Mic
//来个默认值
for i := 1; i <= n; i++ {
mics = append(mics, Mic{
GroupUuid: groupUuid,
I: i,
Lock: false,
MicForbid: false,
})
}
var micUsers []MicUser
//
for k, v := range micMap {
var mic Mic
err = json.Unmarshal([]byte(v), &mic)
if err != nil {
return nil, nil, myerr.WrapErr(err)
}
i, err := strconv.Atoi(k)
if err != nil {
return nil, nil, myerr.WrapErr(err)
}
//麦位是不可能大于5个麦位, 可能存在给部分麦位信息。避免越界
if i <= n {
mics[i-1].Lock = mic.Lock
mics[i-1].MicForbid = mic.MicForbid
}
}
//进行检测,但是没有删除,用户日志判断是否重复
logCheckUserMap := map[string]struct{}{}
for i, _ := range micUsers {
if _, flag := logCheckUserMap[micUsers[i].ExternalId]; flag {
mylogrus.MyLog.Infof("mic repeat groupUid:%v, i:%v, externalId:%v", groupUuid, micUsers[i].I, micUsers[i].ExternalId)
} else {
logCheckUserMap[micUsers[i].ExternalId] = struct{}{}
}
}
//
for k, v := range micUserMap {
var micUser MicUser
err = json.Unmarshal([]byte(v), &micUser)
if err != nil {
return nil, nil, err
}
if err != nil {
return nil, nil, myerr.WrapErr(err)
}
micUser.I = k
micUser.GroupUuid = groupUuid
micUsers = append(micUsers, micUser)
}
micUserCheckMap := map[string]struct{}{}
for i, _ := range micUsers {
if micUsers[i].ExternalId != "" {
if _, flag := micUserCheckMap[micUsers[i].ExternalId]; flag {
mylogrus.MyLog.Errorf("mic user repeat groupUid:%v, i:%v, ExternalId:%v", groupUuid, micUsers[i].I, micUsers[i].ExternalId)
} else {
micUserCheckMap[micUsers[i].ExternalId] = struct{}{}
}
}
}
return mics, micUsers, nil
}
//获取麦位
func GetMic(model *domain.Model, groupUuid string, i int) (*Mic, error) {
if i < 1 || i > 30 {
return nil, myerr.NewSysErrorF("麦序不对,不在范围值内 i:%v", i)
}
str, err := redisCli.GetRedis().HGet(context.Background(), redis_key.GetPrefixGroupMic(groupUuid), strconv.Itoa(i)).Result()
if err != nil {
if err == redisV8.Nil {
return &Mic{
model: model,
GroupUuid: groupUuid,
I: i,
Lock: false,
MicForbid: false,
}, nil
}
}
var mic Mic
err = json.Unmarshal([]byte(str), &mic)
if err != nil {
return nil, myerr.WrapErr(err)
}
return &Mic{
model: model,
GroupUuid: groupUuid,
I: i,
Lock: mic.Lock,
MicForbid: mic.MicForbid,
}, nil
}
//获取用户在哪个麦位上。没有不在麦上,则是nil
func GetMicUserByExternalId(model *domain.Model, externalId string) (*MicUser, error) {
if str, err := redisCli.GetRedis().Get(context.Background(), redis_key.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(), redis_key.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 InitMicNumType(model *domain.Model, groupUuid string, t group_e.GroupMicNumType) *MicNumType {
return &MicNumType{
model: model,
GroupUuid: groupUuid,
T: t,
}
}
//func getMicUserRedisData(userId uint64, forbid bool) string {
// return strconv.Itoa(int(userId)) + "_" + strconv.FormatBool(forbid)
//}
func micToStr(mic Mic) (string, error) {
buf, err := json.Marshal(mic)
if err != nil {
return "", myerr.WrapErr(err)
} else {
return string(buf), nil
}
}
func micUserToStr(micUser MicUser) (string, error) {
buf, err := json.Marshal(micUser)
if err != nil {
return "", myerr.WrapErr(err)
} else {
return string(buf), nil
}
}
func userInMicToStr(groupUuid string, i int, userId uint64) (string, error) {
userInMic := UserInMic{
GroupUuid: groupUuid,
I: i,
UserId: userId,
}
buf, err := json.Marshal(userInMic)
if err != nil {
return "", myerr.WrapErr(err)
} else {
return string(buf), 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
}
// 检查声网状态后再下奖
func (mu *MicUser) CheckAndDown() {
gm, err := GetGroupInfo(mu.model, mu.GroupUuid)
if err == nil && gm != nil {
userListRsp, err := agora.GetUserList(gm.ChannelId)
mu.model.Log.Infof("userListRsp %+v, err: %+v", userListRsp, err)
found := false
if err == nil {
for _, u := range userListRsp.Data.Broadcasters {
if mu.UserId == u {
found = true
break
}
}
}
if !found {
// 确定不在主播列表里,才踢下麦
err = mu.LeaveByUser(mu.UserId, mu.ExternalId)
mu.model.Log.Infof("LeaveByUser err:%v userId:%v", err, mu.UserId)
// 下发通知给客户端弹出提示
if err == nil {
MicSocketMicOutRPush(mu.model, mu.GroupUuid, mu.ExternalId)
}
}
}
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type GroupBanned struct {
mysql.Entity
ImGroupId string
MgrId uint64
RuleId uint64
}
func (banned *GroupBanned) Set(model *domain.Model) error {
return model.Db.Where(banned).Create(banned).Error
}
func (banned *GroupBanned) Get(model *domain.Model) error {
return model.Db.Where(banned).First(banned).Error
}
func (banned *GroupBanned) Delete(model *domain.Model) error {
return model.Db.Where(banned).Delete(&GroupBanned{}).Error
}
func GetBannedGroups(model *domain.Model) ([]GroupBanned, error) {
result := make([]GroupBanned, 0)
err := model.Db.Find(&result).Error
if err != nil {
return nil, err
}
return result, nil
}
func GetBannedGroupsMap(model *domain.Model) (map[string]uint64, error) {
r, err := GetBannedGroups(model)
if err != nil {
return nil, err
}
result := make(map[string]uint64, 0)
for _, i := range r {
result[i.ImGroupId] = i.MgrId
}
return result, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type GroupBlacklist struct {
mysql.Entity
ImGroupId string
UserId uint64
Imei string
Ip string
}
func AddBlacklist(model *domain.Model, gb *GroupBlacklist) error {
return model.Db.Create(gb).Error
}
func RemoveBlacklist(model *domain.Model, gb *GroupBlacklist) error {
return model.Db.Where(gb).Delete(&GroupBlacklist{}).Error
}
func (g *GroupBlacklist) FindUser(model *domain.Model) error {
return model.Db.Where(g).First(g).Error
}
func InGroupBlackList(model *domain.Model, groupId, imei, ip string, userId uint64) bool {
g := GroupBlacklist{ImGroupId: groupId, UserId: userId}
err := g.FindUser(model)
if err == nil {
return true
}
if imei != "" {
g := GroupBlacklist{ImGroupId: groupId, Imei: imei}
err := g.FindUser(model)
if err == nil {
return true
}
}
if ip != "" {
g := GroupBlacklist{ImGroupId: groupId, Ip: ip}
err := g.FindUser(model)
if err == nil {
return true
}
}
return false
}
func FindGroupBlackList(model *domain.Model, groupId string) ([]GroupBlacklist, error) {
result := make([]GroupBlacklist, 0)
err := model.Db.Where(&GroupBlacklist{ImGroupId: groupId}).Find(&result).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, err
}
}
return result, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"time"
)
type GroupCustomTheme struct {
mysql.Entity
*domain.Model `gorm:"-"`
ImGroupId string
PicUrl mysql.Str
ExpireTime time.Time
Using mysql.YesNo
}
func GetGroupCustomThemeById(model *domain.Model, imGroupId string, id mysql.ID) (*GroupCustomTheme, error) {
groupCustomTheme := GroupCustomTheme{}
if err := model.Db.Model(&GroupCustomTheme{
ImGroupId: imGroupId,
}).First(&groupCustomTheme, id).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupCustomTheme.Model = model
return &groupCustomTheme, nil
}
func (groupCustomTheme *GroupCustomTheme) SetUsing(userId mysql.ID) (*GroupCustomTheme, error) {
// 判断有没有权限修改资料
role, err := GetRoleInGroup(groupCustomTheme.Model, userId, groupCustomTheme.ImGroupId)
if err != nil {
return nil, err
}
if role != group_e.GROUP_OWNER && role != group_e.GROUP_MANAGER {
//return nil, myerr.NewSysError("No privileges")
return nil, bizerr.NoPrivileges
}
//将其它的赋值为未使用
if err := groupCustomTheme.Db.Model(&GroupCustomTheme{}).Where(&GroupCustomTheme{ImGroupId: groupCustomTheme.ImGroupId}).UpdateColumn("using", mysql.NO).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupCustomTheme.Using = mysql.YES
return groupCustomTheme, nil
}
func AddGroupCustomTheme(model *domain.Model, userId mysql.ID, imGroupId string, picUrl string) (*GroupCustomTheme, error) {
// 判断有没有权限修改资料
role, err := GetRoleInGroup(model, userId, imGroupId)
if err != nil {
return nil, err
}
if role != group_e.GROUP_OWNER && role != group_e.GROUP_MANAGER {
//return nil, myerr.NewSysError("No privileges")
return nil, bizerr.NoPrivileges
}
var n int64 = 0
if err := model.Db.Model(&GroupCustomTheme{}).Where(&GroupCustomTheme{ImGroupId: imGroupId}).Where("expire_time > ?", time.Now()).Count(&n).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if n >= int64(config.GetGroupCustomThemeConfig().PIC_LIMIT) {
return nil, bizerr.GroupCustomThemeLimit
}
//校验权限,产品没说,应该有
//将其它的赋值为未使用
if err := model.Db.Model(&GroupCustomTheme{}).Where(&GroupCustomTheme{ImGroupId: imGroupId}).UpdateColumn("using", mysql.NO).Error; err != nil {
return nil, myerr.WrapErr(err)
}
picUrl = utils.MakeFullUrl(picUrl)
return &GroupCustomTheme{
Model: model,
ImGroupId: imGroupId,
PicUrl: picUrl,
ExpireTime: time.Now().AddDate(0, 0, config.GetGroupCustomThemeConfig().DAY),
Using: mysql.YES,
}, nil
}
//获取最新展示的主题
func GetShowCustomTheme(model *domain.Model, imGroupId string) (uint64, string, error) {
groupCustomTheme := GroupCustomTheme{}
if err := model.Db.Model(&GroupCustomTheme{}).Where(&GroupCustomTheme{ImGroupId: imGroupId}).Where("expire_time > ?", time.Now()).Order("`using` asc, expire_time asc").First(&groupCustomTheme).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, "", nil
} else {
return 0, "", myerr.WrapErr(err)
}
} else {
return groupCustomTheme.ID, groupCustomTheme.PicUrl, nil
}
}
package group_m
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"github.com/bluele/gcache"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"math/rand"
"time"
)
var (
FuncAddEditGroupCd func(model *domain.Model, imGroupId mysql.Str) error
)
type GroupInfo struct {
Id int64
ImGroupId string
TxGroupId string
Type uint16
Code string
OriginCode string
Owner uint64
Name string
Introduction string
Notification string
FaceUrl string
Country string
ChannelId string
Password string
EntryLevel uint32 // obsolete
MicOn bool
LoadHistory bool
ThemeId int16
MicNumType group_e.GroupMicNumType
TouristMic uint8 // 游客是否能上麦1是2否
TouristSendMsg uint8 // 游客是否能发消息1是2否
TouristSendPic uint8 // 游客是否能发图片1是2否
MemberFee uint64 // 加入会员需要黄钻数
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
}
func GenerateGroupCode(n uint16) string {
const numbers = "0123456789"
b := make([]byte, n)
for i := range b {
if i == 0 {
// 第一个数字不能为0
b[i] = numbers[1+rand.Int()%(len(numbers)-1)]
} else {
b[i] = numbers[rand.Int()%len(numbers)]
}
}
return string(b)
}
func CreateGroup(model *domain.Model, groupInfo *GroupInfo) error {
return model.Db.Create(groupInfo).Error
}
func FindGroupByOwner(model *domain.Model, ownerId uint64) ([]GroupInfo, error) {
rows := make([]GroupInfo, 0)
err := model.Db.Where(&GroupInfo{Owner: ownerId}).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func FindGroupMapByOwner(model *domain.Model, ownerId uint64) (map[string]GroupInfo, error) {
rows, err := FindGroupByOwner(model, ownerId)
if err != nil {
return nil, err
}
result := make(map[string]GroupInfo, 0)
for _, i := range rows {
result[i.ImGroupId] = i
}
return result, nil
}
func FindGroupByOwners(db *gorm.DB, ownerIds []uint64) (map[uint64]GroupInfo, error) {
rows := make([]GroupInfo, 0)
err := db.Model(&GroupInfo{}).Where("owner IN ?", ownerIds).Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[uint64]GroupInfo, 0)
for _, i := range rows {
result[i.Owner] = i
}
return result, nil
}
func UpdateCountryByOwner(model *domain.Model, country string, ownerId uint64) error {
return model.Db.Model(&GroupInfo{}).Where(&GroupInfo{Owner: ownerId}).Update("country", country).Error
}
// fixme: 删除这个函数
func FindGroupByCode(model *domain.Model, code string) (*GroupInfo, error) {
r := GroupInfo{}
err := model.Db.Where(&GroupInfo{Code: code}).First(&r).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, err
}
}
return &r, nil
}
func FindGroupByCodes(db *gorm.DB, codes []string) (map[string]GroupInfo, error) {
rows := make([]GroupInfo, 0)
err := db.Where("code IN ?", codes).Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[string]GroupInfo, 0)
for _, i := range rows {
result[i.Code] = i
}
return result, nil
}
func GetGroupInfo(model *domain.Model, groupId string) (*GroupInfo, error) {
if len(groupId) <= 0 {
return nil, bizerr.GroupNotFound
}
r := GroupInfo{}
err := model.Db.Where(&GroupInfo{ImGroupId: groupId}).First(&r).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, err
}
}
return &r, nil
}
func GetInfoByTxGroupId(model *domain.Model, txGroupId string) (*GroupInfo, error) {
if len(txGroupId) <= 0 {
return nil, bizerr.GroupNotFound
}
r := GroupInfo{}
err := model.Db.Where(&GroupInfo{TxGroupId: txGroupId}).First(&r).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, err
}
}
return &r, nil
}
// 分几次获取
// 每次500只
func BatchGetGroupInfo(model *domain.Model, groupIds []string) (map[string]GroupInfo, error) {
result := make(map[string]GroupInfo, 0)
total := len(groupIds)
if total <= 0 {
return result, nil
}
const NUM = 500
start, end := 0, NUM
for start < total {
if end > total {
end = total
}
tmpGroupId := groupIds[start:end]
data := make([]GroupInfo, 0)
if err := model.Db.Where("im_group_id IN ?", tmpGroupId).Find(&data).Error; err != nil {
return result, err
}
for _, i := range data {
result[i.ImGroupId] = i
}
start += NUM
end += NUM
}
model.Log.Infof("BatchGetGroupInfo expected:%v,actual:%v", len(groupIds), len(result))
if len(groupIds) != len(result) {
model.Log.Warnf("BatchGetGroupInfo expected:%v", groupIds)
}
return result, nil
}
func GetGroupByCode(model *domain.Model, code string) (*GroupInfo, error) {
rows := make([]GroupInfo, 0)
err := model.Db.Where(&GroupInfo{Code: code}).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) > 0 {
return &rows[0], nil
}
return nil, nil
}
func GetGroupByCodes(model *domain.Model, codes []string) (map[string]GroupInfo, error) {
rows := make([]GroupInfo, 0)
err := model.Db.Where("code in (?)", codes).Find(&rows).Error
if err != nil {
return nil, err
}
mapGroup := map[string]GroupInfo{}
for i, _ := range rows {
mapGroup[rows[i].Code] = rows[i]
}
return mapGroup, nil
}
func (g *GroupInfo) Update(model *domain.Model, imGroupId string, fields []string) *gorm.DB {
return model.Db.Model(&GroupInfo{}).Where("im_group_id = ?", imGroupId).Select(fields).Updates(g)
}
func ResetGroupInfo(model *domain.Model, groupId string, code string) error {
name := fmt.Sprintf(utils.DEFAULT_NICK, code)
gi := GroupInfo{
Name: name,
FaceUrl: "",
Introduction: "",
Notification: "",
}
if err := gi.Update(model, groupId, []string{"name", "face_url", "introduction", "notification"}).Error; err != nil {
model.Log.Errorf("ResetGroupInfo fail:%v", err)
return err
}
if err := RemoveWelcomeText(model.Db, groupId); err != nil {
model.Log.Errorf("RemoveWelcomeText fail:%v", err)
return err
}
// 编辑群组资料cd
if err := FuncAddEditGroupCd(model, groupId); err != nil {
model.Log.Warnf("AddEditGroupCd fail %s ", groupId)
}
return nil
}
// 设置群组头像
func SetFaceUrl(model *domain.Model, groupId, faceUrl string) error {
gi := GroupInfo{
FaceUrl: faceUrl,
}
return gi.Update(model, groupId, []string{"face_url"}).Error
}
// 找到所有群
func (g *GroupInfo) FindAllGroups(db *gorm.DB) ([]GroupInfo, error) {
result := make([]GroupInfo, 0)
err := db.Where(g).Find(&result).Error
return result, err
}
func FindNoPasswordGroups(model *domain.Model) ([]GroupInfo, error) {
result := make([]GroupInfo, 0)
err := model.Db.Where("password = ''").Find(&result).Error
return result, err
}
func FindNoPasswordGroupsV2(model *domain.Model, imGroupIds []string) ([]GroupInfo, error) {
result := make([]GroupInfo, 0)
if len(imGroupIds) <= 0 {
return result, nil
}
err := model.Db.Where("im_group_id in ? AND password = ''", imGroupIds).Find(&result).Error
return result, err
}
func GetAllGroupIds(db *gorm.DB) ([]string, error) {
result := make([]GroupInfo, 0)
err := db.Find(&result).Error
if err != nil {
return nil, err
}
groupIds := make([]string, 0)
for _, i := range result {
groupIds = append(groupIds, i.ImGroupId)
}
return groupIds, err
}
var ownerCountryGroupCache = gcache.New(10000).LRU().Build()
// 缓存15分钟
func FindOwnerCountryGroups(model *domain.Model, country string) ([]GroupInfo, error) {
key := fmt.Sprintf("owner:country:group:%s", country)
if data, err := ownerCountryGroupCache.Get(key); err == nil {
model.Log.Infof("FindOwnerCountryGroups hit:%v", len(data.([]GroupInfo)))
return data.([]GroupInfo), nil
}
result := make([]GroupInfo, 0)
//err := model.Db.Model(&GroupInfo{}).Joins("left join user on user.id = owner").Where("user.country = ?", country).Where("password = ''").Find(&result).Error
err := model.Db.Model(&GroupInfo{}).Where(&GroupInfo{
Country: country,
}).Find(&result).Error
_ = ownerCountryGroupCache.SetWithExpire(key, result, time.Minute*15)
return result, err
}
//过滤被封禁的群或者有密码的群
func FilterGroupBannedOrPassword(groupIds []string) (map[string]struct{}, error) {
type result struct {
ImGroupId string
}
results := []result{}
if err := mysql.Db.Model(&GroupInfo{}).Select("im_group_id").Where("im_group_id in (?)", groupIds).Where("password = ''").Where("not EXISTS (SELECT 1 from group_banned b where b.im_group_id = group_info.im_group_id) ").Scan(&results).Error; err != nil {
return nil, myerr.WrapErr(err)
}
imGroupIdSet := map[string]struct{}{}
for i := 0; i < len(results); i++ {
imGroupIdSet[results[i].ImGroupId] = struct{}{}
}
return imGroupIdSet, nil
}
func GetGroupImGroupIdByDbId(model *domain.Model, dbId uint64) (string, error) {
r := GroupInfo{}
//err := model.Db.Model(&GroupInfo{}).First(&r, dbId).Error
//if err != nil {
// return "", myerr.WrapErr(err)
//}
if err := model.Db.Raw("SELECT id, im_group_id from group_info i where i.id = ?", dbId).First(&r).Error; err != nil {
return "", myerr.WrapErr(err)
}
return r.ImGroupId, nil
}
func GetGroupInfoByDbIds(model *domain.Model, dbIds []uint64) (map[mysql.ID]GroupInfo, error) {
type result struct {
Id uint64
GroupInfo
}
rs := []result{}
if err := model.Db.Raw("SELECT * from group_info i where i.id in (?)", dbIds).Scan(&rs).Error; err != nil {
return nil, myerr.WrapErr(err)
}
imGroupMap := map[mysql.ID]GroupInfo{}
for i, _ := range rs {
imGroupMap[rs[i].Id] = rs[i].GroupInfo
}
return imGroupMap, nil
}
func GetGroupCodeByDbId(model *domain.Model, dbId uint64) (string, error) {
type result struct {
Code string
}
r := result{}
if err := model.Db.Raw("SELECT code from group_info i where i.id = ?", dbId).First(&r).Error; err != nil {
return "", myerr.WrapErr(err)
}
return r.Code, nil
}
func GetGroupCodeByDbIds(model *domain.Model, dbIds []uint64) (map[mysql.ID]string, error) {
type result struct {
Id uint64
Code string
}
rs := []result{}
if err := model.Db.Raw("SELECT id, code from group_info i where i.id in (?)", dbIds).Scan(&rs).Error; err != nil {
return nil, myerr.WrapErr(err)
}
imGroupMap := map[mysql.ID]string{}
for i, _ := range rs {
imGroupMap[rs[i].Id] = rs[i].Code
}
return imGroupMap, nil
}
func GetGroupOwnerByDbIds(model *domain.Model, dbIds []uint64) (map[mysql.ID]mysql.ID, error) {
type result struct {
Id uint64
Owner uint64
}
rs := []result{}
if err := model.Db.Raw("SELECT owner, id from group_info i where i.id in (?)", dbIds).Scan(&rs).Error; err != nil {
return nil, myerr.WrapErr(err)
}
imGroupMap := map[mysql.ID]mysql.ID{}
for i, _ := range rs {
imGroupMap[rs[i].Id] = rs[i].Owner
}
return imGroupMap, nil
}
func GetGroupIdByDbIds(model *domain.Model, dbIds []uint64) (map[mysql.ID]string, error) {
type result struct {
Id uint64
ImGroupId string
}
rs := []result{}
if err := model.Db.Raw("SELECT id, im_group_id from group_info i where i.id in (?)", dbIds).Scan(&rs).Error; err != nil {
return nil, myerr.WrapErr(err)
}
imGroupMap := map[mysql.ID]string{}
for i, _ := range rs {
imGroupMap[rs[i].Id] = rs[i].ImGroupId
}
return imGroupMap, nil
}
func GetGroupDbIdByOwner(model *domain.Model, ownerId uint64) (uint64, error) {
type result struct {
Id uint64
}
results := []result{}
if err := model.Db.Raw("SELECT i.id from group_info i where i.owner = ?", ownerId).Scan(&results).Error; err != nil {
return 0, myerr.WrapErr(err)
}
if len(results) == 0 {
return 0, nil
}
return results[0].Id, nil
}
func GetGroupInfoByOwner(model *domain.Model, ownerId uint64) (*GroupInfo, error) {
rows := make([]*GroupInfo, 0)
err := model.Db.Where("owner = ?", ownerId).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) == 0 {
return nil, nil
}
return rows[0], nil
}
func GetGroupDbIdByCode(model *domain.Model, code string) (uint64, error) {
type result struct {
Id uint64
}
results := []result{}
if err := model.Db.Raw("SELECT i.id from group_info i where i.code = ?", code).Scan(&results).Error; err != nil {
return 0, myerr.WrapErr(err)
}
if len(results) == 0 {
return 0, nil
}
return results[0].Id, nil
}
func GetGroupDbIdByCodes(model *domain.Model, codes []string) (map[string]uint64, error) {
type result struct {
Id uint64
Code string
}
results := []result{}
if err := model.Db.Raw("SELECT i.id, i.code from group_info i where i.code in (?)", codes).Scan(&results).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if len(results) == 0 {
return nil, nil
}
rs := map[string]uint64{}
for i, _ := range results {
rs[results[i].Code] = results[i].Id
}
return rs, nil
}
//获取数据库的ID,特殊用途
func GetGroupDbId(model *domain.Model, imGroupId string) (mysql.ID, error) {
type result struct {
Id uint64
}
results := []result{}
if err := model.Db.Raw("SELECT i.id from group_info i where i.im_group_id = ?", imGroupId).Scan(&results).Error; err != nil {
return 0, myerr.WrapErr(err)
}
if len(results) == 0 {
return 0, bizerr.GroupNotFound
}
return results[0].Id, nil
}
var officialGroup []string
func IsOfficialGroup(groupId string) bool {
for _, i := range officialGroup {
if i == groupId {
return true
}
}
return false
}
func GetLatestGroupInfos(model *domain.Model, limit, lastId int, groupIds []string) (res []*GroupInfo, err error) {
if len(groupIds) <= 0 {
return nil, nil
}
res = make([]*GroupInfo, 0)
query := model.Db.Debug().Model(GroupInfo{}).Where("im_group_id IN ?", groupIds)
if lastId > 0 {
query.Where("id < ?", lastId)
}
err = query.Order("id DESC").Limit(limit).Find(&res).Error
return
}
//func init() {
// // 初始化官方群组
// strGroupIds := strings.Split(config.GetConfigApp().OFFICIAL_GROUP, ",")
// for _, i := range strGroupIds {
// if len(i) > 0 {
// officialGroup = append(officialGroup, i)
// }
// }
// mylogrus.MyLog.Info("Official groups: ", officialGroup)
//
// event.AddUserInfoUpdate(func(model *domain.Model, e interface{}) error {
// event := e.(*event.UserInfoUpdateEvent)
// if event.Country == nil {
// return nil
// } else {
// // v2.3需求:同步更新群组country
// model.Log.Infof("Receive userInfoUpdate: user %d, country %s", event.UserId, *event.Country)
// return UpdateCountryByOwner(model, *event.Country, event.UserId)
// }
// })
// event.AddMgrUserCountryUpdateAsync(func(model *domain.Model, event *event.MgrUserCountryUpdateEvent) error {
// // v2.3需求:同步更新群组country
// model.Log.Infof("Receive MgrUserCountryUpdate: user %d, from %s to %s", event.UserId, event.OldCountry, event.NewCountry)
// return UpdateCountryByOwner(model, event.NewCountry, event.UserId)
// })
//}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
//踢人记录
type GroupKickRecord struct {
mysql.Entity
*domain.Model `gorm:"-"`
ImGroupId string
UserId mysql.ID
BeKickUserId mysql.ID
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type GroupUserLimits struct {
mysql.Entity
UserId uint64
MaxJoin uint
}
func (guLimit *GroupUserLimits) Set(model *domain.Model) error {
return model.Db.Where(guLimit).Create(guLimit).Error
}
func (guLimit *GroupUserLimits) Get(model *domain.Model) error {
return model.Db.Where(guLimit).First(guLimit).Error
}
func (guLimit *GroupUserLimits) Delete(model *domain.Model) error {
return model.Db.Where(guLimit).Delete(&GroupUserLimits{}).Error
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"hilo-group/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
}
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
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/myerr"
)
//群组勋章
type GroupMedal struct {
mysql.Entity
*domain.Model `gorm:"-"`
ImGroupId string
ResMedalId uint64
}
func (gm *GroupMedal) Create(db *gorm.DB) (int64, error) {
result := db.Clauses(clause.OnConflict{DoNothing: true}).Create(gm)
return result.RowsAffected, result.Error
}
//增加群组勋章
func (groupInfo *GroupInfo) GroupMedalMgrAdd(model *domain.Model, resMedalId uint64) *GroupMedal {
return &GroupMedal{
Model: model,
ImGroupId: groupInfo.ImGroupId,
ResMedalId: resMedalId,
}
}
func GetGroupMedalOrErr(model *domain.Model, id mysql.ID) (*GroupMedal, error) {
groupMedal := GroupMedal{}
if err := model.Db.Model(&GroupMedal{}).First(&groupMedal, id).Error; err != nil {
return nil, myerr.WrapErr(err)
}
groupMedal.Model = model
return &groupMedal, nil
}
func GetGroupMedalOrInit(model *domain.Model, imGroupId string, resMedalId mysql.ID) (*GroupMedal, error) {
groupMedal := GroupMedal{}
if err := model.Db.Model(&GroupMedal{}).Where(&GroupMedal{
ImGroupId: imGroupId,
ResMedalId: resMedalId,
}).First(&groupMedal).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &GroupMedal{
Model: model,
ImGroupId: imGroupId,
ResMedalId: resMedalId,
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupMedal.Model = model
return &groupMedal, nil
}
func BatchGetMedals(db *gorm.DB, groupIds []string) (map[string][]uint64, error) {
if len(groupIds) <= 0 {
return nil, nil
}
rows := make([]GroupMedal, 0)
if err := db.Model(&GroupMedal{}).Where("im_group_id IN ?", groupIds).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[string][]uint64, 0)
for _, i := range rows {
if _, ok := result[i.ImGroupId]; !ok {
result[i.ImGroupId] = make([]uint64, 0)
}
result[i.ImGroupId] = append(result[i.ImGroupId], i.ResMedalId)
}
return result, nil
}
//移除群组勋章
func (groupMedal *GroupMedal) GroupMedalMgrDel() *GroupMedal {
groupMedal.SetDel()
return groupMedal
}
package group_m
import (
"gorm.io/gorm"
)
type GroupMember struct {
GroupId string
UserId uint64
}
func (gm *GroupMember) Create(db *gorm.DB) error {
return db.Create(gm).Error
}
func (gm *GroupMember) Remove(db *gorm.DB) error {
return db.Where(gm).Delete(&GroupMember{}).Error
}
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 GetMembers(db *gorm.DB, groupId string) ([]GroupMember, error) {
gm := GroupMember{
GroupId: groupId,
}
return gm.Find(db)
}
func GetMemberCount(db *gorm.DB, groupId string) (uint, error) {
gm := GroupMember{
GroupId: groupId,
}
var c int64
if err := db.Model(&GroupMember{}).Where(&gm).Count(&c).Error; err != nil {
return 0, err
}
return uint(c), nil
}
func GetJoinedGroups(db *gorm.DB, userId uint64) ([]GroupMember, error) {
gm := GroupMember{
UserId: userId,
}
return gm.Find(db)
}
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 (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
redis2 "github.com/go-redis/redis/v8"
"hilo-group/_const/redis_key"
"hilo-group/myerr"
"time"
)
/**
* 消息。基于。替代腾讯云的IM的设计。同时考虑消息的性能以及持久化
* 设计:
1:持久化
数据库持久化(全量持久化)
2:消息性能。由于消息数据量很大。不能基于消息数据库查询。数据获取以缓存为主,数据确认以数据库数据为准。
3:缓存数据:异步并接受消息丢失的容错
1:群组最大消息序列号(递增,无过期,删除基于:群组解散)。redis key:group_msg_seq_max_all Map(key:groupUuid, value:序列号)
2:群组用户最大读消息序列号(递增,无过期,删除基于:群组解散) redis key:group_msg_seq_max_{uuid} Map(key:用户名字, value:序列号)
3:群组5分钟内发言的用户(有增有减,删除时间在于增加时候,判断时间是否在5分钟内) redis key:group_msg_duration_user sort set(key:群组Id_用户ID,score:时间戳)
     4:群组优先级发言的得分(依据于用户数)。(有增有减少,触发时机:群组5分钟内的发言数量) redis key:group_msg_duration_score sortSet (key:群组Id, score:得分(用户数))
*/
//redis的群组最大消息序列号
type RediGroupMsgSeqMax struct {
//序列号
Seq uint64
//群组ID
GroupUuid string
}
//设置新的序列号
func (rediGroupMsgSeqMax *RediGroupMsgSeqMax) NewSeq(seq uint64) *RediGroupMsgSeqMax {
rediGroupMsgSeqMax.Seq = seq
return rediGroupMsgSeqMax
}
//redis的群组用户最大消息序列号
type RedisGroupMsgSeqMaxUser struct {
//群组ID
GroupUuid string
//用户ExternalId
ExternalId string
//序列号
Seq uint64
}
//redis的群组用户最大消息序列号
func (redisGroupMsgSeqMaxUser *RedisGroupMsgSeqMaxUser) NewSeq(seq uint64) *RedisGroupMsgSeqMaxUser {
redisGroupMsgSeqMaxUser.Seq = seq
return redisGroupMsgSeqMaxUser
}
//redis的群组期间用户发言
type RedisGroupMsgDurationUser struct {
//群组ID
GroupUuid string
//用户ExternalId
ExternalId string
//时间戳
TimeStamp int64
}
//群组中发言的数量
type RedisGroupMsgDurationScore struct {
//群组ID
GroupUuid string
//用户的数量, 负数减少
AddCountUser int
}
//减少次数
func (redisGroupMsgDurationScore *RedisGroupMsgDurationScore) reduce() {
redisGroupMsgDurationScore.AddCountUser = redisGroupMsgDurationScore.AddCountUser - 1
}
//增加次数
func (redisGroupMsgDurationScore *RedisGroupMsgDurationScore) add() *RedisGroupMsgDurationScore {
redisGroupMsgDurationScore.AddCountUser = redisGroupMsgDurationScore.AddCountUser + 1
return redisGroupMsgDurationScore
}
//删除
func GroupUserMsgDurationDel(redisGroupUserMsgDurations []*RedisGroupMsgDurationUser) ([]*RedisGroupMsgDurationScore, error) {
groupMsgCountUserMap := map[string]*RedisGroupMsgDurationScore{}
for i := 0; i < len(redisGroupUserMsgDurations); i++ {
if redisGroupMsgCountUser, ok := groupMsgCountUserMap[redisGroupUserMsgDurations[i].GroupUuid]; ok {
redisGroupMsgCountUser.reduce()
} else {
redisGroupMsgCountUser, err := getRedisGroupMsgDurationScoreInit(redisGroupUserMsgDurations[i].GroupUuid)
if err != nil {
return nil, err
}
redisGroupMsgCountUser.reduce()
groupMsgCountUserMap[redisGroupUserMsgDurations[i].GroupUuid] = redisGroupMsgCountUser
}
}
//for _, v := range redisGroupUserMsgDurations {
// if redisGroupMsgCountUser, ok := groupMsgCountUserMap[v.GroupUuid]; ok {
// redisGroupMsgCountUser.reduce()
// } else {
// redisGroupMsgCountUser, err := getRedisGroupMsgDurationScoreInit(v.GroupUuid)
// if err != nil {
// return nil, err
// }
// redisGroupMsgCountUser.reduce()
// groupMsgCountUserMap[v.GroupUuid] = redisGroupMsgCountUser
// }
//}
groupMsgCountUserList := []*RedisGroupMsgDurationScore{}
for k, _ := range groupMsgCountUserMap {
groupMsgCountUserList = append(groupMsgCountUserList, groupMsgCountUserMap[k])
}
return groupMsgCountUserList, nil
}
//持久化,群组消息
type GroupMsg struct {
mysql.Entity
*domain.Model `gorm:"-"`
CallbackCommand string
GroupId string
Type string //类型
FromAccount string //发送者
OperatorAccount string //请求的发送者
Random int //随机数
MsgSeq uint64
MsgTime uint64
OnlineOnlyFlag uint8
MsgBody string
}
//获取最近说话的排序
func GetRecentSort() ([]string, error) {
//查找周期性是否存在
if groupUuidsStr, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupMsgDurationScoreSnap()).Result(); err != nil {
//没有,则重新生成
if err == redis2.Nil {
//移除得分为0的
_, err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetPrefixGroupMsgDurationScore(), "0", "0").Result()
if err != nil {
//容错,只是打印错误
mylogrus.MyLog.Infoln("redis group_msg_duration_score ZRemRangeByScore err:%v", err)
}
//倒叙获取所有的分数
// ZREVRANGEBYSCORE salary +inf -inf
if groupUuids, err := redisCli.GetRedis().ZRevRangeByScore(context.Background(), redis_key.GetPrefixGroupMsgDurationScore(), &redis2.ZRangeBy{
Min: "-inf",
Max: "+inf",
}).Result(); err != nil {
return nil, myerr.WrapErr(err)
} else {
//重新加入
bytes, err := json.Marshal(groupUuids)
if err != nil {
return nil, myerr.WrapErr(err)
}
if err := redisCli.GetRedis().SetEX(context.Background(), redis_key.GetPrefixGroupMsgDurationScoreSnap(), string(bytes), time.Duration(config.GetGroupImConfig().MSG_SORT_SNAP)*time.Second).Err(); err != nil {
return nil, myerr.WrapErr(err)
} else {
return groupUuids, nil
}
}
} else {
return nil, myerr.WrapErr(err)
}
} else {
groupUuids := []string{}
if err := json.Unmarshal([]byte(groupUuidsStr), &groupUuids); err != nil {
return nil, myerr.WrapErr(err)
}
return groupUuids, nil
}
}
//
//func init() {
// //由于redis在执行数据读写过程中,是单线程,并且有数据的统计,是属于递增/递减 n,或者数据集直接拿出来畜栏里, 因此就是存在并发,也不影响数据的一致性。
// event.AddGroupMsgNewAsync(func(model *domain.Model, event *event.GroupMsgNewEvent) error {
// model.Log.Infof("GroupMsgNewAsync groupMsg GroupUuid:%v, FromAccount:%v, MsgSeq:%v, MsgTime:%v", event.GroupUuid, event.FromAccount, event.MsgSeq, event.MsgTime)
// //redis中群组中最大的消息序列
// rediGroupMsgMaxSeq, err := getRediGroupMsgMaxSeqOrInit(event.GroupUuid)
// if err != nil {
// return err
// }
// if err := rediGroupMsgMaxSeq.NewSeq(event.MsgSeq).Persistent(); err != nil {
// return err
// }
// /* //用户在群中的最大消息序列,
// redisGroupUserMsgMaxSeq, err := getRedisGroupUserMsgMaxSeqOrInit(event.GroupUuid, event.FromAccount)
// if err != nil {
// return err
// }
// if err := redisGroupUserMsgMaxSeq.Persistent(); err != nil {
// return err
// }*/
// //查找已到过期时间的消息
// redisGroupUserMsgDurations, err := getExpireRedisGroupUserMsgDuration()
// if err != nil {
// return err
// }
// redisGroupMsgCountUsers, err := GroupUserMsgDurationDel(redisGroupUserMsgDurations)
// for i := 0; i < len(redisGroupMsgCountUsers); i++ {
// if err := redisGroupMsgCountUsers[i].Persistent(); err != nil {
// return err
// }
// }
// //增加一条记录,
// i, err := initRedisGroupUserMsgDuration(event.GroupUuid, event.FromAccount).Persistent()
// if err != nil {
// return err
// }
// //如果是新增,则开始增加一条记录
// if i > 0 {
// redisGroupMsDurationScore, err := getRedisGroupMsgDurationScoreInit(event.GroupUuid)
// if err != nil {
// return err
// }
// if err := redisGroupMsDurationScore.add().Persistent(); err != nil {
// return err
// }
// }
// return nil
// })
// //发送消息
// //发送
//
// //幸运转盘创建
// event.AddLuckyWheelCreateAsync(func(model *domain.Model, event *event.LuckyWheelCreateEvent) error {
// model.Log.Infof("groupMsg AddLuckyWheelCreateAsync LuckyWheelId:%v, CreateUserId:%v, GroupUid:%v, LuckyWheelSeatId:%v", event.LuckyWheelId, event.CreateUserId, event.GroupUid, event.LuckyWheelSeatId)
// /* if err != nil {
// model.Log.Errorf("msg AddLuckyWheelCreateAsync RoomLivingExistsUserId err:%v, groupUid:%v", err, event.GroupUid)
// }
// if err := consul.SendLuckyWheel(event.GroupUid, userIds, consul.LuckyWheelCreate); err != nil {
// model.Log.Errorf("msg AddLuckyWheelCreateAsync SendLuckyWheel err:%v", err)
// }*/
// context, _ := json.Marshal(map[string]interface{}{"type": consul.LuckyWheelCreate})
// sendSignalMsg(model, event.GroupUid, GroupSystemMsg{
// MsgId: group_enum.GroupLuckyWheel,
// Content: string(context),
// }, true)
// return nil
// })
//
// //幸运转盘Play
// event.AddLuckyWheelPlayAsync(func(model *domain.Model, event *event.LuckyWheelPlayEvent) error {
// model.Log.Infof("groupMsg AddLuckyWheelPlayAsync LuckyWheelId:%v, GroupUid:%v", event.LuckyWheelId, event.GroupUid)
// /* userIds, err := group_m.RoomLivingExistsUserId(event.GroupUid)
// if err != nil {
// model.Log.Errorf("msg AddLuckyWheelPlayAsync RoomLivingExistsUserId err:%v, groupUid:%v", err, event.GroupUid)
// }
// if err := consul.SendLuckyWheel(event.GroupUid, userIds, consul.LuckyWheelPlay); err != nil {
// model.Log.Errorf("msg AddLuckyWheelPlayAsync SendLuckyWheel err:%v", err)
// }*/
// context, _ := json.Marshal(map[string]interface{}{"type": consul.LuckyWheelPlay})
// sendSignalMsg(model, event.GroupUid, GroupSystemMsg{
// MsgId: group_enum.GroupLuckyWheel,
// Content: string(context),
// }, true)
// return nil
// })
//
// //幸运转盘加入
// event.AddLuckyWheelJoinAsync(func(model *domain.Model, event *event.LuckyWheelJoinEvent) error {
// model.Log.Infof("groupMsg AddLuckyWheelJoinAsync LuckyWheelId:%v, GroupUid:%v", event.LuckyWheelId, event.GroupUid)
// /* userIds, err := group_m.RoomLivingExistsUserId(event.GroupUid)
// if err != nil {
// model.Log.Errorf("msg AddLuckyWheelJoinAsync RoomLivingExistsUserId err:%v, groupUid:%v", err, event.GroupUid)
// }
// if err := consul.SendLuckyWheel(event.GroupUid, userIds, consul.LuckyWheelUserJoin); err != nil {
// model.Log.Errorf("msg AddLuckyWheelJoinAsync SendLuckyWheel err:%v", err)
// }*/
// context, _ := json.Marshal(map[string]interface{}{"type": consul.LuckyWheelUserJoin})
// sendSignalMsg(model, event.GroupUid, GroupSystemMsg{
// MsgId: group_enum.GroupLuckyWheel,
// Content: string(context),
// }, true)
// return nil
// })
//
// //转盘超时回滚
// event.AddLuckyWheelTimeOutAsync(func(model *domain.Model, event *event.LuckyWheelTimeOutEvent) error {
// model.Log.Infof("groupMsg AddLuckyWheelTimeOutAsync LuckyWheelId:%v, GroupUid:%v", event.LuckyWheelId, event.GroupUid)
// /* userIds, err := group_m.RoomLivingExistsUserId(event.GroupUid)
// if err != nil {
// model.Log.Errorf("msg AddLuckyWheelTimeOutAsync RoomLivingExistsUserId err:%v, groupUid:%v", err, event.GroupUid)
// }
// if err := consul.SendLuckyWheel(event.GroupUid, userIds, consul.LuckyWheelUserTimeOut); err != nil {
// model.Log.Errorf("msg AddLuckyWheelTimeOutAsync SendLuckyWheel err:%v", err)
// }*/
// context, _ := json.Marshal(map[string]interface{}{"type": consul.LuckyWheelUserTimeOut})
// sendSignalMsg(model, event.GroupUid, GroupSystemMsg{
// MsgId: group_enum.GroupLuckyWheel,
// Content: string(context),
// }, true)
// return nil
// })
//
// //幸运转盘user取消
// event.AddLuckyWheelCancelAsync(func(model *domain.Model, event *event.LuckyWheelCancelEvent) error {
// model.Log.Infof("msg AddLuckyWheelCancelAsync LuckyWheelId:%v, GroupUid:%v", event.LuckyWheelId, event.GroupUid)
// /* userIds, err := group_m.RoomLivingExistsUserId(event.GroupUid)
// if err != nil {
// model.Log.Errorf("msg AddLuckyWheelCancelAsync RoomLivingExistsUserId err:%v, groupUid:%v", err, event.GroupUid)
// }
// if err := consul.SendLuckyWheel(event.GroupUid, userIds, consul.LuckyWheelUserCancel); err != nil {
// model.Log.Errorf("msg AddLuckyWheelCancelAsync SendLuckyWheel err:%v", err)
// }*/
// context, _ := json.Marshal(map[string]interface{}{"type": consul.LuckyWheelUserCancel})
// sendSignalMsg(model, event.GroupUid, GroupSystemMsg{
// MsgId: group_enum.GroupLuckyWheel,
// Content: string(context),
// }, true)
// return nil
// })
//}
package group_m
import "git.hilo.cn/hilo-common/domain"
type GroupPopular struct {
GroupId string
}
func GetPopularWhiteList(model *domain.Model) (map[string]struct{}, error) {
rows := make([]GroupPopular, 0)
err := model.Db.Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[string]struct{}, 0)
for _, i := range rows {
result[i.GroupId] = struct{}{}
}
return result, nil
}
func (gp *GroupPopular) Add(model *domain.Model) error {
return model.Db.Create(gp).Error
}
func (gp *GroupPopular) Delete(model *domain.Model) error {
return model.Db.Where(gp).Delete(&GroupPopular{}).Error
}
\ No newline at end of file
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/enum/group_e"
)
//举报群
type GroupReport struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupId mysql.Str
UserId mysql.ID
MsgStatus group_e.MsgStatusGroupUser
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/group_e"
)
type GroupRoles struct {
mysql.Entity
UserId uint64
ImGroupId string
Role group_e.GroupRoleType
}
func CreateGroupRole(model *domain.Model, imGroupId string, userId uint64, role group_e.GroupRoleType) error {
return model.Db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}, {Name: "im_group_id"}},
DoUpdates: clause.AssignmentColumns([]string{"role"}),
}).Create(&GroupRoles{
UserId: userId,
ImGroupId: imGroupId,
Role: role,
}).Error
}
func RemoveGroupRole(model *domain.Model, imGroupId string, userId uint64) error {
return model.Db.Where(&GroupRoles{ImGroupId: imGroupId, UserId: userId}).Delete(&GroupRoles{}).Error
}
// 查询用户在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 FindRolesInGroup(db *gorm.DB, imGroupId string, role group_e.GroupRoleType) ([]uint64, error) {
rows := make([]GroupRoles, 0)
err := db.Model(&GroupRoles{}).Where(&GroupRoles{
Role: role,
ImGroupId: imGroupId}).Order("created_time").Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]uint64, 0)
for _, i := range rows {
result = append(result, i.UserId)
}
return result, nil
}
// 统计IM群组中某角色的个数
func GetRoleCountInGroup(model *domain.Model, imGroupId string, role group_e.GroupRoleType) (uint, error) {
var count int64 = 0
err := model.Db.Model(&GroupRoles{}).Where(&GroupRoles{
Role: role,
ImGroupId: imGroupId}).Count(&count).Error
if err != nil {
return 0, err
}
return uint(count), nil
}
// 统计用户在所有群中的角色
func GetRolesByUser(model *domain.Model, userId uint64) (map[string]uint16, error) {
data := make([]GroupRoles, 0)
err := model.Db.Where(&GroupRoles{UserId: userId}).Find(&data).Error
if err != nil {
return nil, err
}
result := make(map[string]uint16, 0)
for _, i := range data {
result[i.ImGroupId] = i.Role
}
return result, nil
}
// 查询群组中所有有角色的成员,由级别高到低、创建时间由早到晚排列
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 IsRoleGreater(model *domain.Model, groupId string, userId1, userId2 uint64) (bool, error) {
m, _, err := GetRolesInGroup(model, groupId)
if err != nil {
return false, err
}
return m[userId1] > m[userId2], nil
}
func GetGroupOwner(model *domain.Model, groupId string) (uint64, error) {
gr := GroupRoles{ImGroupId: groupId, Role: group_e.GROUP_OWNER}
err := model.Db.Where(&gr).First(&gr).Error
if err != nil && err != gorm.ErrRecordNotFound {
return 0, err
}
return gr.UserId, nil
}
func GetGroups(db *gorm.DB, userId uint64, role group_e.GroupRoleType) ([]string, error) {
gr := GroupRoles{UserId: userId, Role: role}
rows := make([]GroupRoles, 0)
err := db.Where(&gr).Order("created_time").Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]string, 0)
for _, i := range rows {
result = append(result, i.ImGroupId)
}
return result, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/group_e"
)
type GroupSetting struct {
mysql.Entity
GroupId string
DiceNum uint16
DiceType uint16
ProfitAllocator uint64
IsHidden bool
}
// 冲突时只更新diceNum
func (gs *GroupSetting) SetDiceNum(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"dice_num"}),
}).Create(gs).Error
}
// 冲突时只更新diceType
func (gs *GroupSetting) SetDiceType(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"dice_type"}),
}).Create(gs).Error
}
// 冲突时只更新IsHidden
func (gs *GroupSetting) SetIsHidden(db *gorm.DB) error {
gs.DiceNum = group_e.GROUP_DICE_NUM_DEFAULT
return db.Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"is_hidden"}),
}).Create(gs).Error
}
func (gs *GroupSetting) GetHidden(db *gorm.DB) (map[string]struct{}, error) {
rows := make([]GroupSetting, 0)
result := make(map[string]struct{}, 0)
gs.IsHidden = true
if err := db.Where(gs).Find(&rows).Error; err != nil {
return nil, err
}
for _, i := range rows {
result[i.GroupId] = struct{}{}
}
return result, nil
}
func IsHiddenGroup(db *gorm.DB, groupId string) (bool, error) {
gs := GroupSetting{IsHidden: true}
hiddenGroups, err := gs.GetHidden(db)
if err != nil {
return false, err
} else {
_, ok := hiddenGroups[groupId]
return ok, nil
}
}
func (gs *GroupSetting) Get(db *gorm.DB) error {
return db.Where(gs).First(gs).Error
}
func GetProfitAllocator(model *domain.Model, groupId string) (uint64, error) {
gs := GroupSetting{GroupId: groupId}
err := gs.Get(model.Db)
if err != nil && err != gorm.ErrRecordNotFound {
return 0, err
}
if gs.ProfitAllocator > 0 {
return gs.ProfitAllocator, nil
} else {
owner, err := GetGroupOwner(model, groupId)
if err != nil {
return 0, err
}
return owner, nil
}
}
package group_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"time"
)
type GroupSupporter struct {
mysql.Entity
GroupId string
UserId uint64
}
func (gs *GroupSupporter) Get(db *gorm.DB) ([]uint64, error) {
rows := make([]GroupSupporter, 0)
err := db.Model(&GroupSupporter{}).Where(gs).Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]uint64, 0)
for _, i := range rows {
result = append(result, i.UserId)
}
return result, nil
}
// 根据时间返回支持鼓励的放送周期
func GetLastSupportPeriod(t time.Time) (time.Time, time.Time, string) {
t = t.AddDate(0,0,-group_e.SUPPORT_LEVEL_PERIOD_DAY)
return GetSupportLevelTime(t)
}
func (gs *GroupSupporter) Delete(db *gorm.DB) error {
return db.Where(gs).Delete(&GroupSupporter{}).Error
}
func (gs *GroupSupporter) BatchSave(db *gorm.DB, userIds []uint64) error {
records := make([]GroupSupporter, 0)
for _, i := range userIds {
records = append(records, GroupSupporter{
GroupId: gs.GroupId,
UserId: i,
})
}
return db.Create(&records).Error
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
)
type GroupTop struct {
Id uint
ImGroupId string
}
func (g *GroupTop) PutOnTop(model *domain.Model) error {
err := model.Db.Model(&GroupTop{}).Where("id > 0").Order("id DESC").UpdateColumn("id", gorm.Expr("id + ?", 1)).Error
if err != nil {
return err
}
g.Id = 1
return model.Db.Create(g).Error
}
func (g *GroupTop) Delete(model *domain.Model) error {
return model.Db.Where(g).Delete(&GroupTop{}).Error
}
func GroupTopGetAll(model *domain.Model) ([]string, error) {
rows := make([]GroupTop, 0)
err := model.Db.Order("id").Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]string, 0)
for _, i := range rows {
result = append(result, i.ImGroupId)
}
return result, err
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/enum/group_e"
"time"
)
//群与人,
//设定(用户的当前状态)
type GroupUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupId mysql.Str
UserId mysql.ID
MsgStatus group_e.MsgStatusGroupUser
InRoomTime *time.Time //进入房间的时间
}
func (groupUser *GroupUser) MsgStatusNormal() *GroupUser {
groupUser.MsgStatus = group_e.NormalMsgStatusGroupUser
return groupUser
}
func (groupUser *GroupUser) MsgStatusMute() *GroupUser {
groupUser.MsgStatus = group_e.MuteMsgStatusGroupUser
return groupUser
}
func (groupUser *GroupUser) MsgStatusDoNotDisturb() *GroupUser {
groupUser.MsgStatus = group_e.DoNotDisturbMsgStatusGroupUser
return groupUser
}
//删除
func (groupUser *GroupUser) Del() *GroupUser {
groupUser.SetDel()
return groupUser
}
//修改进入房间的时间
func (groupUser *GroupUser) SetRoomInTime() *GroupUser {
now := time.Now()
groupUser.InRoomTime = &now
return groupUser
}
func (groupUser *GroupUser) Get() (map[string]group_e.MsgStatusGroupUser, error) {
rows := make([]GroupUser, 0)
err := groupUser.Db.Where(groupUser).Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[string]group_e.MsgStatusGroupUser, 0)
for _, i := range rows {
result[i.GroupId] = i.MsgStatus
}
return result, nil
}
func (groupUser *GroupUser) Delete() error {
return groupUser.Db.Where(groupUser).Delete(&GroupUser{}).Error
}
package group_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// 群欢迎语
type GroupWelcomeText struct {
mysql.Entity
GroupId mysql.Str
UserId mysql.ID
Text mysql.Str
}
func (gwt *GroupWelcomeText) Save(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "group_id"}},
DoUpdates: clause.AssignmentColumns([]string{"text", "user_id"}),
}).Create(gwt).Error
}
func (gwt *GroupWelcomeText) Remove(db *gorm.DB, groupId string, userId uint64) error {
cond := GroupWelcomeText{GroupId: groupId, UserId: userId}
return db.Where(&cond).Delete(gwt).Error
}
func (gwt *GroupWelcomeText) Get(db *gorm.DB) (*GroupWelcomeText, error) {
rows := make([]GroupWelcomeText, 0)
err := db.Where(gwt).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) <= 0 {
return nil, nil
}
return &rows[0], nil
}
func RemoveWelcomeText(db *gorm.DB, groupId string) error {
cond := GroupWelcomeText{GroupId: groupId}
return db.Where(&cond).Delete(&GroupWelcomeText{}).Error
}
package group_m
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"github.com/bluele/gcache"
redis2 "github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/user_m"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"runtime/debug"
"strconv"
"strings"
"time"
)
/**
1: 主要关注点:分布式事务一致性,高效。
2:存储介质:redis,理由:不重要,高频数据请求,持久化过程注意点:利用redis单次操作作为原子性,利用原子性的操作结果(判断更新数量,成败)来保证整个麦位的原子性操作。
3:分布式事务一致性(声网,服务器)。以服务端数据为准。客户端保持同声网数据一致。5分钟C端请求服务的信息,进行同步,纠正声网数据不一致问题。
4: 存储结构:
ps: micUser持久话动作,没有归属于repo,因为需要处理并发下一致性问题。因此,在方法中,进行持久化,
*/
/**
* redis记录。
micHasGroup -> set, 定于:可能麦上有人的群组(确保:麦上有人一定在该集合中), 增加时机:加入麦位之前, 减少时机:利用lua表达式控制顺序,没有人在麦上,则清理数据。(lua防止并发,麦上有人后,被移除出数据)
micNumType -> groupUuid string, 有生命周期,缓存不存在的时候,就找数据库,更新:先删除缓存,再修改数据库。
核心:mic -> groupUuid Map(key:i, value:Mic) 为了减少redis的数据,当mic的值为默认值时,执行的HDel
micUser -> groupUuid Map(key:i value:MicUser)
userInMic -> map(key:extendId, value:MicUser) PS:userInMic同micUser 具有一致性。(原子操作)作用:用于查询某个用户在哪个麦上
*/
//麦位数量类型
type MicNumType struct {
model *domain.Model
GroupUuid string
T group_e.GroupMicNumType
}
const MaxMicNum = 20
//清理缓存
func (micNumType *MicNumType) ClearCache() {
micNumType.model.Log.Infof("group_m MicNumType ClearCache groupUuid:%v", micNumType.GroupUuid)
_, err := redisCli.GetRedis().Del(context.Background(), redis_key.GetPrefixGroupMicNumType(micNumType.GroupUuid)).Result()
if err != nil {
micNumType.model.Log.Errorf("group_m MicNumType ClearCache groupUuid:%v err:%v", micNumType.GroupUuid, err)
}
}
//同步到缓存,用set,强制修改值
func (micNumType *MicNumType) AddCache() error {
micNumType.model.Log.Infof("group_m MicNumType AddCache groupUuid:%v, groupMicNumType:%v", micNumType.GroupUuid, micNumType.T)
_, err := redisCli.GetRedis().Set(context.Background(), redis_key.GetPrefixGroupMicNumType(micNumType.GroupUuid), strconv.Itoa(int(micNumType.T)), micExpire).Result()
if err != nil {
micNumType.model.Log.Errorf("MicNumType add redis set err:%v", err)
return err
}
return nil
}
//获取数据,先从缓存中获取,没有则从数据库中获取,如果不存在,则同步到redis, 必须用setnx,避免同修改的时候,并发让缓存错误。
func GetMicNumType(model *domain.Model, groupUuid string) (group_e.GroupMicNumType, error) {
t, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupMicNumType(groupUuid)).Result()
if err != nil {
if err != redis2.Nil {
return 0, myerr.WrapErr(err)
} else {
//获取数据库的值,同步到缓存
groupInfo, _ := GetGroupInfo(model, groupUuid)
if groupInfo == nil {
return 0, bizerr.GroupNotFound
}
flag, err := redisCli.GetRedis().SetNX(context.Background(), redis_key.GetPrefixGroupMicNumType(groupUuid), strconv.Itoa(int(groupInfo.MicNumType)), micExpire).Result()
model.Log.Infof("GetMicNumType redis SetNX groupUuid:%v, flag:%v, err:%v", groupUuid, flag, err)
return groupInfo.MicNumType, nil
}
} else {
groupMicNumType, err := strconv.ParseUint(t, 10, 8)
if err != nil {
return 0, nil
}
return group_e.GroupMicNumType(groupMicNumType), nil
}
}
//6个小时
const expireMinute = 60 * 60 * 12
const micExpire = expireMinute * time.Second
//麦位基本信息。
type Mic struct {
model *domain.Model
//群组uuid
GroupUuid string
//麦位
I int
//锁,是否有锁 true:锁了, false:没锁
Lock bool
//麦位静音
MicForbid bool
}
//发言,注意(发言是在麦位上)
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
}
//60*5
//const micInExpireScript = "local flag = redis.call('expire', '{prefixGroupMicUser}', '300') if flag == 1 then return redis.call('expire', '{prefixGroupUserMic}', '300') end return 0 "
//先让user在那个麦上续时间,再让麦上有谁续时间? 目前日志统计中,并没有发现只执行一半的,全部执行成功。
const micInExpireScript = "local flag = redis.call('expire', '{prefixGroupMicUser}', '{micExpire}') if flag == 1 then return redis.call('expire', '{prefixGroupUserMic}', '{micExpire}') end return 0 "
func UpdateMicExpire(model *domain.Model, groupUuid string, externalId string) error {
micUser, err := GetMicUserByExternalId(model, externalId)
if err != nil {
return err
}
//
if micUser != nil {
if micUser.GroupUuid == groupUuid {
//使用lua表达式
script := strings.Replace(
strings.Replace(
strings.Replace(micInExpireScript, "{micExpire}", strconv.Itoa(expireMinute), -1), "{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(micUser.GroupUuid, micUser.I), -1), "{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1)
//redisCli.GetRedis().ScriptFlush(context.Background())
n, err := redis2.NewScript(script).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
if n == 0 {
mylogrus.MyLog.Infof("UpdateMicExpire script result:n=%v", n)
}
if err != nil {
return myerr.WrapErr(err)
}
//存在才更新。
/* if flag, err := redisCli.GetRedis().Expire(context.Background(), redis.GetPrefixGroupUserInMic(externalId), micExpire).Result(); err == nil {
if flag {
redisCli.GetRedis().Expire(context.Background(), redis.GetPrefixGroupMicUser(micUser.GroupUuid, micUser.I), micExpire)
//基本一致,接受容错,如果担心错误,可以反向验证。目前不考虑。因为这个接口频率太高了。
}
}*/
}
}
return nil
}
//12个小时
//2022-07-20 升级,判断是自己是否已经在别的麦上了
//const micInScript = "local flag = redis.call('SET', '{prefixGroupMicUser}', '{micUserStr}', 'ex', '{micExpire}', 'nx') if flag ~= false then redis.call('SETEX', '{prefixGroupUserMic}', '{micExpire}', '{groupUserStr}') return 1 end return 2 "
const micInScript = "local flag = redis.call('EXISTS', '{prefixGroupUserMic}') if flag == 0 then local flag1 = redis.call('SET', '{prefixGroupMicUser}', '{micUserStr}', 'ex', '{micExpire}', 'nx') if flag1 ~= false then redis.call('SETEX', '{prefixGroupUserMic}', '{micExpire}', '{groupUserStr}') return 1 end return 2 end return 3"
//
//上麦(自己),
//规则:1:加锁了不能上麦 2:麦上有人,不能上麦
func (mic *Mic) In(userId uint64, externalId string) error {
// 群是否被封禁, 呃,,,呃,,,呃,,,
banned := GroupBanned{ImGroupId: mic.GroupUuid}
if err := banned.Get(mic.model); err != gorm.ErrRecordNotFound {
return bizerr.GroupIsBanned
}
//判断群组设置上的麦 是否被关闭
groupInfo, err := GetGroupInfo(mic.model, mic.GroupUuid)
if err != nil {
return err
}
if groupInfo.MicOn == false {
return bizerr.GroupInfoMicClosed
}
//麦被加锁了
if mic.Lock {
return bizerr.GroupMicLock
}
//设置值到redis
micUserStr, err := micUserToStr(MicUser{
GroupUuid: mic.GroupUuid,
I: mic.I,
ExternalId: externalId,
UserId: userId,
Forbid: false,
Timestamp: time.Now().Unix(),
})
if err != nil {
return err
}
//让自己踢出去。
/* if str, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupUserInMic(externalId)).Result(); err != nil {
if err != redis2.Nil {
return myerr.WrapErr(err)
}
} else {
if userInMic, err := strToUserInMic(str); err != nil {
return err
} else {
if micUser, err := GetMicUser(mic.model, userInMic.GroupUuid, userInMic.I); err != nil {
return err
} else {
if micUser != nil {
if err := micUser.LeaveByUser(userId, externalId); err != nil {
return err
}
}
}
}
}*/
//加入到麦上可能有人的集合中。
groupMicHasIn(mic.model, mic.GroupUuid, userId)
//lua上麦,让麦上的人同人在麦上,保持原子性操作
//清理脚本,不然redis占用内存越来越高,并且不会释放
groupUserStr, err := userInMicToStr(mic.GroupUuid, mic.I, userId)
if err != nil {
return err
}
//r, err := redis2.NewScript(micInScript).Run(context.Background(), redisCli.GetRedis(), []string{redis.GetPrefixGroupMicUser(mic.groupUuid), strconv.Itoa(mic.i), redis.GetPrefixGroupUserMic(), externalId}, micUserStr, groupUserStr).Result()
script := strings.Replace(strings.Replace(
strings.Replace(
strings.Replace(
strings.Replace(micInScript, "{micExpire}", strconv.Itoa(expireMinute), -1), "{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(mic.GroupUuid, mic.I), -1), "{micUserStr}", micUserStr, -1), "{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1), "{groupUserStr}", groupUserStr, -1)
//redisCli.GetRedis().ScriptFlush(context.Background())
r, err := redis2.NewScript(script).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
mic.model.Log.Infof("micUser In micInScript:%v, result:%v", script, r)
d := r.(int64)
if err != nil {
return myerr.WrapErr(err)
}
if d == int64(2) {
return bizerr.GroupMicHasUser
}
if d == int64(3) {
return bizerr.GroupMicUserHasIn
}
//离开动作已结束,增加到队列中
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicInSignal,
Source: externalId,
}, false)
return nil
}
const micLeaveScript = "local flag = redis.call('DEL', '{prefixGroupMicUser}') if flag == 1 then return redis.call('Del', '{prefixGroupUserMic}') end return 2 "
//离开麦(自己)
//规则:1:自己的麦
func (micUser *MicUser) leave(operateUserId uint64, operateExternalId string) error {
//
if micUser == nil {
return bizerr.GroupMicNoUser
}
//
externalId := micUser.ExternalId
if micUser.ExternalId != operateExternalId {
//检查权限,管理人权限, 不过不拥有管理人权限,则抛出错误
if err := MgrPermission(micUser.model, micUser.GroupUuid, operateUserId, micUser.UserId); err != nil {
return err
}
}
//设置值到redis
//redisCli.GetRedis().ScriptFlush(context.Background())
script := strings.Replace(strings.Replace(
micLeaveScript, "{prefixGroupMicUser}", redis_key.GetPrefixGroupMicUser(micUser.GroupUuid, micUser.I), -1), "{prefixGroupUserMic}", redis_key.GetPrefixGroupUserInMic(externalId), -1)
r, err := redis2.NewScript(script).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
d := r.(int64)
micUser.model.Log.Infof("micUser leave micLeaveScript:%v, result:%v", script, d)
if err != nil {
return err
}
if d == 2 {
//不在该麦位上,可能被redis,过期移除了。
//return bizerr.GroupMicErr
}
//离开动作已结束,增加到队列中
MicChangeRPush(micUser.model, micUser.GroupUuid, micUser.I)
return nil
}
//邀请的翻译
var inviteMicMsgTranslate = map[string]string{}
//邀请上麦
func InviteMicIn(model *domain.Model, groupUuid string, operateUserId uint64, beInvitedExternalId string) error {
model.Log.Infof("mic InviteMicIn operateUserId:%d, beInvitedExternalId:%s", operateUserId, beInvitedExternalId)
if err := CheckPermission(model, groupUuid, operateUserId); err != nil {
return err
}
user, err := user_m.GetUser(model, operateUserId)
if err != nil {
return err
}
beInvitedUser, err := user_m.GetUserByExtId(model, beInvitedExternalId)
if err != nil {
return err
}
context, ok := inviteMicMsgTranslate[beInvitedUser.Language]
if ok == false {
context = inviteMicMsgTranslate["en"]
}
context = strings.Replace(context, "{nick}", user.Nick, -1)
sendSignalMsg(model, groupUuid, GroupSystemMsg{
MsgId: group_e.GroupInviteMicInSignal,
Source: user.ExternalId,
Target: beInvitedExternalId,
Content: context,
}, false)
return nil
}
// 用户操作下麦(自己或者管理人)fixme: 参数往往是错的
func (micUser *MicUser) LeaveByUser(operateUserId uint64, operateExternalId string) error {
micUser.model.Log.Infof("mic LeaveByUser userId:%d", operateUserId)
if err := micUser.leave(operateUserId, operateExternalId); err != nil {
return err
}
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(micUser.model, micUser.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicOutSignal,
Source: operateExternalId,
}, false)
return nil
}
/*func (micUser *MicUser) LeaveBySocket(operateUserId uint64, operateExternalId string) error {
micUser.model.Log.Infof("mic leaveBySocket userId:%d", operateUserId)
if err := micUser.leave(operateUserId, operateExternalId); err != nil {
return err
}
// 发信令,让前端重新拉取,接受容错,
go func(groupId, externalId string) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("SendCustomMsg: LeaveBySocket SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
sendSignalMsg(groupId, GroupSystemMsg{
MsgId: group_e.GroupSocketMicOutSignal,
Source: externalId,
})
}(micUser.GroupUuid, operateExternalId)
return nil
}*/
//锁。(管理人加锁)
//规则:1:麦上有人,不能锁 2:必须是管理人以上岗位
//Multi EXEC, 保证了加锁的时候,没有人
func (mic *Mic) MgrLock(userId uint64, externalId string) error {
//获取麦上的人
micUser, err := GetMicUser(mic.model, mic.GroupUuid, mic.I)
if err != nil {
return err
}
//
if micUser != nil {
return bizerr.GroupMicHasUser
}
//判断权限
if err := CheckPermission(mic.model, mic.GroupUuid, userId); err != nil {
return err
}
mic.Lock = true
//设置值到redis
micStr, err := micToStr(*mic)
if err != nil {
return err
}
if _, err = redisCli.GetRedis().HSet(context.Background(), redis_key.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I), micStr).Result(); err != nil {
return myerr.WrapErr(err)
}
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicLockSignal,
Source: externalId,
}, false)
return nil
}
//去除锁。(管理人解锁)
//规则,必须是管理人才能解锁
func (mic *Mic) MgrUnLock(userId uint64, externalId string) error {
//判断权限
if err := CheckPermission(mic.model, mic.GroupUuid, userId); err != nil {
return err
}
//判断权限
mic.Lock = false
//移除
if _, err := redisCli.GetRedis().HDel(context.Background(), redis_key.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I)).Result(); err != nil {
return myerr.WrapErr(err)
}
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicUnLockSignal,
Source: externalId,
}, false)
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
return nil
//设置值到redis
/* micStr, err := micToStr(*mic)
if err != nil {
return err
}
if _, err = redisCli.GetRedis().HSet(context.Background(), redis.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I), micStr).Result(); err != nil {
return myerr.WrapErr(err)
}
return nil*/
}
// 麦位静音
func (mic *Mic) MgrMute(userId uint64, externalId string) error {
//判断权限
if err := CheckPermission(mic.model, mic.GroupUuid, userId); err != nil {
return err
}
mic.MicForbid = true
//设置值到redis
micStr, err := micToStr(*mic)
if err != nil {
return err
}
if _, err = redisCli.GetRedis().HSet(context.Background(), redis_key.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I), micStr).Result(); err != nil {
return myerr.WrapErr(err)
}
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicLockSignal,
Source: externalId,
}, false)
return nil
}
// 麦位解除静音
func (mic *Mic) MgrUnMute(userId uint64, externalId string) error {
//判断权限
if err := CheckPermission(mic.model, mic.GroupUuid, userId); err != nil {
return err
}
// 移除
if _, err := redisCli.GetRedis().HDel(context.Background(), redis_key.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I)).Result(); err != nil {
return myerr.WrapErr(err)
}
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(mic.model, mic.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicUnLockSignal,
Source: externalId,
}, false)
MicChangeRPush(mic.model, mic.GroupUuid, mic.I)
return nil
//设置值到redis
/* micStr, err := micToStr(*mic)
if err != nil {
return err
}
if _, err = redisCli.GetRedis().HSet(context.Background(), redis.GetPrefixGroupMic(mic.GroupUuid), strconv.Itoa(mic.I), micStr).Result(); err != nil {
return myerr.WrapErr(err)
}
return nil*/
}
//开麦, 管理人 同 自己能开麦
//规则:1:自己开麦 2:管理人开麦
func (micUser *MicUser) SpeechOpen(userId uint64, externalId string) error {
if micUser == nil {
return bizerr.GroupMicNoUser
} else {
if micUser.ExternalId == externalId {
micUser.Forbid = false
} else {
//检查是不是管理人
if err := CheckPermission(micUser.model, micUser.GroupUuid, userId); err != nil {
return err
}
micUser.Forbid = false
}
}
//设置值到redis
micUserStr, err := micUserToStr(*micUser)
if err != nil {
return err
}
if _, err = redisCli.GetRedis().Set(context.Background(), redis_key.GetPrefixGroupMicUser(micUser.GroupUuid, micUser.I), micUserStr, micExpire).Result(); err != nil {
return myerr.WrapErr(err)
} else {
redisCli.GetRedis().Expire(context.Background(), redis_key.GetPrefixGroupUserInMic(externalId), micExpire)
}
MicChangeRPush(micUser.model, micUser.GroupUuid, micUser.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(micUser.model, micUser.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicSpeechOpenSignal,
Source: externalId,
}, false)
return nil
}
//禁麦, 管理人 同 自己能禁麦(特别注意:产品说,无论是否式管理人开启禁麦,自己同管理人都能关闭禁麦)
//规则:1:自己禁麦 2:管理人禁麦
func (micUser *MicUser) SpeechClose(userId uint64, externalId string) error {
if micUser == nil {
return bizerr.GroupMicNoUser
} else {
//自己
if micUser.ExternalId == externalId {
micUser.Forbid = true
} else if flag, err := user_m.IsSuperManager(micUser.model, micUser.UserId); err != nil {
return err
} else if flag {
//不能让超级管理人移除
return bizerr.OfficialStaffLimit
} else if flag, err := user_m.IsSuperManager(micUser.model, userId); err != nil {
return err
} else if flag {
//超级管理人,无敌状态
micUser.Forbid = true
} else {
//检查是不是管理人
if err := CheckPermission(micUser.model, micUser.GroupUuid, userId); err != nil {
return err
}
//检查是否是贵族
if flag, err := noble_m.CheckNobleLevel(micUser.model.Db, micUser.UserId, 5); err != nil {
return err
} else if flag {
return bizerr.NobleNoMicSpeechCloseLevel5
}
micUser.Forbid = true
}
}
//设置值到redis
micUserStr, err := micUserToStr(*micUser)
if err != nil {
return err
}
if _, err := redisCli.GetRedis().Set(context.Background(), redis_key.GetPrefixGroupMicUser(micUser.GroupUuid, micUser.I), micUserStr, micExpire).Result(); err != nil {
return myerr.WrapErr(err)
} else {
redisCli.GetRedis().Expire(context.Background(), redis_key.GetPrefixGroupUserInMic(externalId), micExpire)
}
MicChangeRPush(micUser.model, micUser.GroupUuid, micUser.I)
// 发信令,让前端重新拉取,接受容错,
sendSignalMsg(micUser.model, micUser.GroupUuid, GroupSystemMsg{
MsgId: group_e.GroupMicSpeechCloseSignal,
Source: externalId,
}, false)
return nil
}
//群发消息
func (micUser *MicUser) ImMass(externalId string) error {
if micUser == nil || micUser.ExternalId != externalId {
return bizerr.GroupMicNoYou
}
//检查权限
if err := CheckPermission(micUser.model, micUser.GroupUuid, micUser.UserId); err != nil {
return err
}
return nil
}
//检查权限,管理人权限, 不过不拥有管理人权限,则抛出错误
func MgrPermission(model *domain.Model, groupUuid string, userId1 uint64, userId2 uint64) error {
if flag, err := IsRoleGreater(model, groupUuid, userId1, userId2); err != nil {
return err
} else {
if flag == false {
return bizerr.GroupMicNoPermission
}
}
return nil
}
//检查权限
func CheckPermission(model *domain.Model, groupUuid string, userId uint64) error {
role, err := GetRoleInGroup(model, userId, groupUuid)
if err != nil {
return err
}
if role == group_e.GROUP_VISITOR || role == group_e.GROUP_MEMBER {
return bizerr.NoPrivileges
}
return nil
}
// 入参是内部使用的imGroupId,先进行转化
func sendSignalMsg(model *domain.Model, groupId string, msg GroupSystemMsg, isSyn bool) {
groupId, err := ToTxGroupId(model, groupId)
if err != nil {
return
}
if isSyn {
sendSignalMsgOnly(groupId, msg)
} else {
go func() {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("sendSignalMsg SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
sendSignalMsgOnly(groupId, msg)
}()
}
}
//发送tengxunyun的系统消息
func sendSignalMsgOnly(groupId string, msg GroupSystemMsg) {
buffer, err := json.Marshal(msg)
if err == nil {
if err = tencentyun.SendSystemMsg(mylogrus.MyLog.WithField("msgId", msg.MsgId), groupId, []string{}, string(buffer)); err != nil {
mylogrus.MyLog.Warnf("SendSystemMsg failed for %s, msgId = %d", groupId, msg.MsgId)
}
} else {
mylogrus.MyLog.Errorf("Marshall failure, msgId = %d : %s", msg.MsgId, err.Error())
}
}
//清理所有麦上的人,强制清理,没有抛出错误,用户接到封禁信令之后,退出麦(必须,用于容错redis清理错误),退出房间
func ClearMic(groupId string) {
//清理10个,麦位从5个变成10 20211025, 改成20 20210628
for i := 1; i <= MaxMicNum; i++ {
//
micUserStr, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetPrefixGroupMicUser(groupId, i)).Result()
if err != nil {
if err == redis2.Nil {
mylogrus.MyLog.Infof("clearMic noUser groupId:%v, i:%v", groupId, i)
} else {
mylogrus.MyLog.Errorf("clearMic err groupId:%v, i:%v, err:%v", groupId, i, err)
continue
}
} else {
var micUser MicUser
if err = json.Unmarshal([]byte(micUserStr), &micUser); err != nil {
mylogrus.MyLog.Errorf("clearMic groupId:%v, i:%v, err:%v", groupId, i, err)
continue
}
//删除
n, err := redisCli.GetRedis().Del(context.Background(), redis_key.GetPrefixGroupMicUser(groupId, i), redis_key.GetPrefixGroupUserInMic(micUser.ExternalId)).Result()
mylogrus.MyLog.Infof("clearMic del groupId:%v, i:%v, result:%v, err:%v", groupId, i, n, err)
//增加到队列中
MicEmptyRPush(domain.CreateModelNil(), groupId, i)
}
}
}
//检查改群组是否麦上有人. true:存在。
func CheckGroupMicHasUser(groupId string) (bool, error) {
//麦位从5个变成10, 20211025
keys := make([]string, 0, 10)
for i := 1; i <= MaxMicNum; i++ {
keys = append(keys, redis_key.GetPrefixGroupMicUser(groupId, i))
/* n, err := redisCli.GetRedis().Exists(context.Background(), redis.GetPrefixGroupMicUser(groupId, i)).Result()
if err != nil {
return false, myerr.WrapErr(err)
}
if n > 0 {
return true, nil
}*/
}
//
if n, err := redisCli.GetRedis().Exists(context.Background(), keys...).Result(); err != nil {
return false, myerr.WrapErr(err)
} else {
if n > 0 {
return true, nil
} else {
return false, nil
}
}
}
//麦上进入了人,不是核心业务,为了辅助过滤。
func groupMicHasIn(model *domain.Model, groupId string, userId mysql.ID) {
model.Log.Infof("groupMicHasIn groupId:%v", groupId)
if n, err := redisCli.GetRedis().SAdd(context.Background(), redis_key.GetPrefixGroupMicHasIn(), groupId).Result(); err != nil {
model.Log.Errorf("groupMicHasIn groupId:%v err:%v", groupId, err)
} else {
println(n)
}
if _, err := redisCli.GetRedis().ZAdd(context.Background(), redis_key.GetPrefixGroupMicHasInUserTime(), &redis2.Z{
Score: float64(time.Now().Unix()),
Member: getMemberStr(groupId, userId),
}).Result(); err != nil {
model.Log.Errorf("groupMicHasIn redis:GetPrefixGroupMicHasInTime groupId:%v err:%v", groupId, err)
}
}
const micHasInScript = "local flag = redis.call('EXISTS', '{key1}', '{key2}', '{key3}', '{key4}', '{key5}', '{key6}', '{key7}', '{key8}', '{key9}', '{key10}', '{key11}', '{key12}', '{key13}', '{key14}', '{key15}', '{key16}', '{key17}', '{key18}', '{key19}', '{key20}') if flag == 0 then redis.call('Srem', '{key}', '{remKey}') end return flag "
//获取麦上有人的群组
func GetMicHasInGroups() ([]string, error) {
//清理lua缓存
//redisCli.GetRedis().ScriptFlush(context.Background())
//获取所有可能存在的人
groupUuids, err := redisCli.GetRedis().SMembers(context.Background(), redis_key.GetPrefixGroupMicHasIn()).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
//
resultGroupUuids := make([]string, 0, len(groupUuids))
//循环lua判断是否, 最后的保证,(猜想:真正麦上有人的群没有很多)
for n, r := range groupUuids {
s := strings.Replace(micHasInScript, "{key}", redis_key.GetPrefixGroupMicHasIn(), -1)
s = strings.Replace(s, "{remKey}", r, -1)
for i := 1; i <= MaxMicNum; i++ {
s = strings.Replace(s, "{key"+strconv.Itoa(i)+"}", redis_key.GetPrefixGroupMicUser(r, i), -1)
}
r, err := redis2.NewScript(s).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
d := r.(int64)
if d > 0 {
resultGroupUuids = append(resultGroupUuids, groupUuids[n])
}
}
return resultGroupUuids, nil
}
type micGroupNumKeyS struct{}
// mic位数量缓存
var micGroupNumKey = micGroupNumKeyS{}
var micGroupNumCache = gcache.New(10000).LRU().Build()
// 获取麦上有人的群组&&麦上的人数
// 带lru缓存,1min
func GetMicHasInGroupNum(model *domain.Model) (map[string]int64, error) {
// get from cache
if data, err := micGroupNumCache.Get(micGroupNumKey); err == nil {
model.Log.Infof("GetMicHasInGroupNum cache hit:%v", data)
// 正服才缓存
if config.AppIsRelease() {
return data.(map[string]int64), nil
}
}
//清理lua缓存
//redisCli.GetRedis().ScriptFlush(context.Background())
//获取所有可能存在的人
groupUuids, err := redisCli.GetRedis().SMembers(context.Background(), redis_key.GetPrefixGroupMicHasIn()).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
//
resultGroupUuids := make(map[string]int64, len(groupUuids))
//循环lua判断是否, 最后的保证,(猜想:真正麦上有人的群没有很多)
for n, r := range groupUuids {
s := strings.Replace(micHasInScript, "{key}", redis_key.GetPrefixGroupMicHasIn(), -1)
s = strings.Replace(s, "{remKey}", r, -1)
for i := 1; i <= MaxMicNum; i++ {
s = strings.Replace(s, "{key"+strconv.Itoa(i)+"}", redis_key.GetPrefixGroupMicUser(r, i), -1)
}
//r, err := redis2.NewScript(s).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
sha1, err := model.Redis.ScriptLoad(model, s).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
micNum, err := model.Redis.EvalSha(model, sha1, nil, nil).Int64()
if err != nil {
return nil, myerr.WrapErr(err)
}
//d := r.(int64)
if micNum > 0 {
resultGroupUuids[groupUuids[n]] = micNum
}
}
// cache 1min
_ = micGroupNumCache.SetWithExpire(micGroupNumKey, resultGroupUuids, time.Minute)
model.Log.Infof("GetMicHasInGroupNum cache miss:%v", resultGroupUuids)
return resultGroupUuids, nil
}
//获取麦上有人的群组&&麦上的数(有时间性,目前是24小时)
func GetMicHasInPeriodGroupUser() (map[string][]uint64, error) {
//清理超过12小时的
if _, err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetPrefixGroupMicHasInUserTime(), "0", strconv.FormatUint(uint64(time.Now().Unix()-24*60*60), 10)).Result(); err != nil {
return nil, myerr.WrapErr(err)
}
groupUserIdstrs, err := redisCli.GetRedis().ZRange(context.Background(), redis_key.GetPrefixGroupMicHasInUserTime(), 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
result := map[string][]uint64{}
for i, _ := range groupUserIdstrs {
tempGroupUid, tempUserId := analysisMemberStr(groupUserIdstrs[i])
if _, flag := result[tempGroupUid]; flag {
result[tempGroupUid] = append(result[tempGroupUid], tempUserId)
} else {
result[tempGroupUid] = []uint64{tempUserId}
}
}
return result, nil
}
//获取麦上有人的群组
func GetMicUserNum(groupUuid string) (uint64, error) {
//清理lua缓存
//redisCli.GetRedis().ScriptFlush(context.Background())
//循环lua判断是否
s := strings.Replace(micHasInScript, "{key}", redis_key.GetPrefixGroupMicHasIn(), -1)
s = strings.Replace(s, "{remKey}", groupUuid, -1)
for i := 1; i <= MaxMicNum; i++ {
s = strings.Replace(s, "{key"+strconv.Itoa(i)+"}", redis_key.GetPrefixGroupMicUser(groupUuid, i), -1)
}
r, err := redis2.NewScript(s).Run(context.Background(), redisCli.GetRedis(), []string{}).Result()
if err != nil {
return 0, myerr.WrapErr(err)
}
d := r.(uint64)
return d, nil
}
func GetMicNum(micNumType group_e.GroupMicNumType) int {
var micNum int = 0
if micNumType == group_e.OneMicNumType {
micNum = 1
} else if micNumType == group_e.TwoMicNumType {
micNum = 2
} else if micNumType == group_e.ThreeMicNumType {
micNum = 3
} else if micNumType == group_e.FourMicNumType {
micNum = 4
} else if micNumType == group_e.FiveMicNumType {
micNum = 5
} else if micNumType == group_e.SixMicNumType {
micNum = 6
} else if micNumType == group_e.SevenMicNumType {
micNum = 7
} else if micNumType == group_e.EightMicNumType {
micNum = 8
} else if micNumType == group_e.NineMicNumType {
micNum = 9
} else if micNumType == group_e.TenMicNumType {
micNum = 10
} else if micNumType == group_e.ElevenMicNumType {
micNum = 11
} else if micNumType == group_e.TwelveMicNumType {
micNum = 12
} else if micNumType == group_e.ThirteenMicNumType {
micNum = 13
} else if micNumType == group_e.FourteenMicNumType {
micNum = 14
} else if micNumType == group_e.FifteenMicNumType {
micNum = 15
} else if micNumType == group_e.SixteenMicNumType {
micNum = 16
} else if micNumType == group_e.SeventeenMicNumType {
micNum = 17
} else if micNumType == group_e.EighteenMicNumType {
micNum = 18
} else if micNumType == group_e.NineteenMicNumType {
micNum = 19
} else if micNumType == group_e.TwentyMicNumType {
micNum = 20
}
return micNum
}
func init() {
//初始化翻译
{
inviteMicMsgTranslate["zh"] = "{nick} 邀请你上麦"
inviteMicMsgTranslate["en"] = "{nick} invite you to take mic"
inviteMicMsgTranslate["ar"] = "يدعوك٪ {nick} إلى أخذ الميكروفون"
inviteMicMsgTranslate["tr"] = "{nick}, sizi mikrofonda konuşmaya davet ediyor"
inviteMicMsgTranslate["id"] = "{nick} mengundangmu menggunakan mic"
inviteMicMsgTranslate["ru"] = "{nick} пригласить тебя появиться у микрофона."
inviteMicMsgTranslate["ko"] = "{nick} 당신에게 마이크 요청합니다"
inviteMicMsgTranslate["pt"] = "{nick} convida você para pegar o mic"
inviteMicMsgTranslate["th"] = "{nick}เชิญคุณเข้าร่วมไมค์"
inviteMicMsgTranslate["ca"] = "{nick} te invito al micrófono"
inviteMicMsgTranslate["hi"] = "{nick} ने आपको माइक लेने के लिए आमंत्रित करता है"
inviteMicMsgTranslate["vi"] = "{nick} mời bạn lên Micrô"
inviteMicMsgTranslate["ur"] = "{nick} کیطرف سے آپ کو مائیک کی دعوت دی گئی ہے"
}
}
package group_m
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"time"
)
//麦位,要发送的麦位信息
type MicSystemMsg struct {
GroupUid string //房间ID
Source string
Target string
MsgId group_e.TypeSignalMsg
Content string //要发送的内容
}
type MicContent struct {
//GroupId
GroupId string `json:"groupId"`
//麦位
I int `json:"i"`
//锁,是否有锁 true:锁了, false:没锁
Lock bool `json:"lock"`
//个人静音 true:静音,false:没有静音
Forbid bool `json:"forbid"`
//麦位静音 true:静音,false:没有静音
MicForbid bool `json:"micForbid"`
//如果 空字符串 则代表这个位置上没有人
ExternalId string `json:"externalId"`
//声网agoraId 如果 0 则代表这个位置上没有人
AgoraId uint32 `json:"agoraId"`
//服务器记录的时间戳
Timestamp int64 `json:"timestamp"`
//用户
User *MicUserData `json:"user"`
}
type MicUserData 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"`
IsVip bool `json:"isVip"`
NobleLeave uint16 `json:"noble"` // 当前的贵族等级
HeadwearPicUrl string `json:"headwearPicUrl"`
HeadwearEffectUrl string `json:"headwearEffectUrl"`
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
}
type MicNumChangeContent struct {
MicOn bool `json:"micOn"`
MicNumType group_e.GroupMicNumType `json:"micNumType"`
Timestamp int64 `json:"timestamp"`
}
func MicGroupKickOutRPush(model *domain.Model, groupUid string, userExternalId string, beKickExternalId string) {
model.Log.Infof("MicChangeRPush MicGroupKickOutRPush begin groupUuid:%v", groupUid)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush ToTxGroupId err:%+v, groupUid:%v", err, groupUid)
}
r := MicNumChangeContent{
Timestamp: time.Now().Unix(),
}
buf, err := json.Marshal(r)
if err != nil {
model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush Content json.Marshal err:%+v", err)
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
Source: userExternalId,
Target: beKickExternalId,
MsgId: group_e.GroupKickOut,
Content: string(buf),
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicGroupKickOutRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
} else {
model.Log.Infof("MicChangeRPush MicGroupKickOutRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
}
model.Log.Infof("MicChangeRPush MicGroupKickOutRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}
func MicSocketMicOutRPush(model *domain.Model, groupUid string, userExternalId string) {
model.Log.Infof("MicChangeRPush MicSocketMicOutRPush begin groupUuid:%v", groupUid)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush ToTxGroupId err:%+v, groupUid:%v", err, groupUid)
}
r := MicNumChangeContent{
Timestamp: time.Now().Unix(),
}
buf, err := json.Marshal(r)
if err != nil {
model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush Content json.Marshal err:%+v", err)
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
Source: userExternalId,
MsgId: group_e.GroupSocketMicOutSignal,
Content: string(buf),
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicSocketMicOutRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
} else {
model.Log.Infof("MicChangeRPush MicSocketMicOutRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
}
model.Log.Infof("MicChangeRPush MicSocketMicOutRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}
func MicNumChangeRPush(model *domain.Model, groupUid string, micNumType group_e.GroupMicNumType, micOn bool) {
model.Log.Infof("MicChangeRPush MicNumChangeRPush begin groupUuid:%v, micNumType:%v", groupUid, micNumType)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicNumChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
}
r := MicNumChangeContent{
MicOn: micOn,
MicNumType: micNumType,
Timestamp: time.Now().Unix(),
}
buf, err := json.Marshal(r)
if err != nil {
model.Log.Errorf("MicChangeRPush MicNumChangeRPush Content json.Marshal err:%+v", err)
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
MsgId: group_e.GroupMicChangeSignal,
Content: string(buf),
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicNumChangeRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicNumChangeRPush err:%+v, groupUuid:%v, micContent:%+v", err, groupUid, string(str))
return
} else {
model.Log.Infof("MicChangeRPush MicNumChangeRPush success groupUuid:%v, micContent:%+v", groupUid, string(str))
}
model.Log.Infof("MicChangeRPush MicNumChangeRPush end groupUuid:%v, micContent:%v", groupUid, string(str))
}
func MicEmptyRPush(model *domain.Model, groupUid string, i int) {
model.Log.Infof("MicChangeRPush MicEmptyRPush begin groupUuid:%v, i:%v", groupUid, i)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicEmptyRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
}
micContent, err := json.Marshal(MicContent{
GroupId: txGroupId,
I: i,
Lock: false,
Forbid: false,
ExternalId: "",
AgoraId: 0,
Timestamp: time.Now().UnixNano(),
User: nil,
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicEmptyRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
return
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
MsgId: group_e.GroupMicChange,
Content: string(micContent),
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicEmptyRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
return
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicEmptyRPush err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContent))
return
} else {
model.Log.Infof("MicChangeRPush MicEmptyRPush success groupUuid:%v, i:%v, micContent:%+v", micContent, groupUid, i, string(micContent))
}
model.Log.Infof("MicChangeRPush MicEmptyRPush end groupUuid:%v, i:%v, micContent:%v", groupUid, i, string(micContent))
}
//将麦位信息推送到redis 队列中
func MicChangeRPush(model *domain.Model, groupUid string, i int) {
model.Log.Infof("MicChangeRPush MicChangeRPush begin groupUuid:%v, i:%v", groupUid, i)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
}
micContent, err := getMicIContent(model, groupUid, i)
if err != nil {
model.Log.Errorf("MicChangeRPush MicChangeRPush getMicIContent err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, micContent)
return
}
micContentStr, err := json.Marshal(micContent)
if err != nil {
model.Log.Errorf("MicChangeRPush MicChangeRPush Marshal err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
return
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
Content: string(micContentStr),
MsgId: group_e.GroupMicChange,
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicChangeRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
return
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicChangeRPush err:%+v, groupUuid:%v, i:%v, micContent:%+v", err, groupUid, i, string(micContentStr))
return
} else {
model.Log.Infof("MicChangeRPush MicChangeRPush success groupUuid:%v, i:%v, micContent:%+v", groupUid, i, string(micContentStr))
}
model.Log.Infof("MicChangeRPush MicChangeRPush end groupUuid:%v, i:%v, micContent:%+v", groupUid, i, micContent)
}
func MicAllRPush(model *domain.Model, groupUid string, externalId string) error {
model.Log.Infof("MicChangeRPush MicAllRPush begin groupUuid:%v, externalId:%v", groupUid, externalId)
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicChangeRPush ToTxGroupId err:%+v, groupUid:%v", err, txGroupId)
}
//
micContents, err := getMicAllContent(model, groupUid)
if err != nil {
model.Log.Errorf("MicChangeRPush MicAllRPush getMicAllContent err:%+v, micContents:%v groupUuid:%v, externalId:%v", err, micContents, groupUid, externalId)
return err
}
for _, micContent := range micContents {
//麦上是默认值,就不用推
if micContent.Forbid == false && micContent.User == nil && micContent.AgoraId == 0 && micContent.Lock == false && micContent.ExternalId == "" && micContent.MicForbid == false {
model.Log.Infof("MicChangeRPush MicAllRPush default micContent:%v, groupUuid:%v, externalId:%v, micContent:%+v", micContent, groupUid, externalId, micContent)
continue
}
micContentStr, err := json.Marshal(micContent)
if err != nil {
model.Log.Errorf("MicChangeRPush MicAllRPush Marshal micContent err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
continue
}
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
Target: externalId,
Content: string(micContentStr),
MsgId: group_e.GroupMicChange,
})
if err != nil {
model.Log.Errorf("MicChangeRPush MicAllRPush Marshal MicSystemMsg err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
continue
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicChangeRPush MicAllRPush err:%+v, groupUuid:%v, externalId:%v, micContent:%+v", err, groupUid, externalId, string(micContentStr))
continue
} else {
model.Log.Infof("MicChangeRPush MicAllRPush success micContent:%v, groupUuid:%v, externalId:%v, micContent:%+v", micContent, groupUid, externalId, string(micContentStr))
}
}
model.Log.Infof("MicChangeRPush MicAllRPush end groupUuid:%v, externalId:%v", groupUid, externalId)
return nil
}
// 通用麦位信息推送
func MicRPush(model *domain.Model, txGroupId string, msg GroupSystemMsg) error {
model.Log.Infof("MicRPush begin msg:%v", msg)
str, err := json.Marshal(MicSystemMsg{
GroupUid: txGroupId,
Source: msg.Source,
MsgId: msg.MsgId,
Content: msg.Content,
})
if err != nil {
model.Log.Errorf("MicRPush Marshal MicSystemMsg err:%+v, txGroupId:%v, micContent:%+v", err, txGroupId, string(str))
return err
}
if n, err := redisCli.GetRedis().RPush(context.Background(), redis_key.GetMicInfoChange(), string(str)).Result(); err != nil || n == 0 {
model.Log.Errorf("MicRPush err:%+v, txGroupId:%v, micContent:%+v", err, txGroupId, string(str))
return err
}
model.Log.Infof("MicRPush end txGroupId:%v, micContent:%v", txGroupId, string(str))
return nil
}
//得使用旧的imGroupId
func getMicAllContent(model *domain.Model, groupUid string) ([]MicContent, error) {
txGroupId, err := ToTxGroupId(model, groupUid)
if err != nil {
return nil, err
}
micNumType, err := GetMicNumType(model, groupUid)
if err != nil {
return nil, err
}
mics, micUsers, err := GetAllMic(groupUid, micNumType)
micUserMap := map[int]MicUser{}
for i, r := range micUsers {
micUserMap[r.I] = micUsers[i]
}
userIds := make([]uint64, 0, len(micUsers))
for _, r := range micUsers {
userIds = append(userIds, r.UserId)
}
model.Log.Infof("MicChangeRPush getMicAllContent groupUid:%v, userIds:%+v", groupUid, userIds)
micUserDataMap, err := getMicUserDatas(model, userIds)
if err != nil {
return nil, err
}
micContents := make([]MicContent, 0, len(mics))
for _, r := range mics {
micContents = append(micContents, MicContent{
GroupId: txGroupId,
I: r.I,
Lock: r.Lock,
MicForbid: r.MicForbid,
Forbid: micUserMap[r.I].Forbid,
ExternalId: micUserMap[r.I].ExternalId,
AgoraId: uint32(micUserMap[r.I].UserId),
Timestamp: time.Now().UnixNano(),
User: micUserDataMap[micUserMap[r.I].UserId],
})
}
return micContents, nil
}
//得使用旧的imGroupId
func getMicIContent(model *domain.Model, groupId string, i int) (MicContent, error) {
txGroupId, err := ToTxGroupId(model, groupId)
if err != nil {
return MicContent{}, err
}
mic, err := GetMic(model, groupId, i)
if err != nil {
return MicContent{}, err
}
micUser, err := GetMicUser(model, groupId, i)
if err != nil {
return MicContent{}, err
}
if micUser == nil {
return MicContent{
GroupId: txGroupId,
I: mic.I,
Lock: mic.Lock,
Forbid: false,
MicForbid: mic.MicForbid,
ExternalId: "",
AgoraId: 0,
Timestamp: time.Now().UnixNano(),
User: nil,
}, nil
} else {
micUserData, err := getMicUserData(model, micUser.UserId)
if err != nil {
return MicContent{}, err
}
return MicContent{
GroupId: txGroupId,
I: mic.I,
Lock: mic.Lock,
Forbid: micUser.Forbid,
MicForbid: mic.MicForbid,
ExternalId: micUser.ExternalId,
AgoraId: uint32(micUser.UserId),
Timestamp: time.Now().UnixNano(),
User: micUserData,
}, nil
}
}
func getMicUserDatas(model *domain.Model, userIds []uint64) (map[uint64]*MicUserData, error) {
userMap, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return nil, err
}
vipMap, err := user_m.BatchGetVips(userIds)
if err != nil {
return nil, err
}
nobleMap, err := noble_m.BatchGetNobleLevel(model.Db, userIds)
if err != nil {
return nil, err
}
headwearMap, err := user_m.BatchGetUserHeadwearUsing(model, userIds)
if err != nil {
return nil, err
}
//
resHeadwearIds := make([]uint64, 0, len(headwearMap))
for _, value := range headwearMap {
resHeadwearIds = append(resHeadwearIds, value.HeadwearId)
}
//
resHeadwearMap, err := res_m.BatchGetHeadwearByIds(model, resHeadwearIds)
if err != nil {
return nil, err
}
svips, _ := rpc.MGetUserSvip(model, userIds)
micUserDataMap := map[uint64]*MicUserData{}
for _, id := range userIds {
user, flag := userMap[id]
if !flag {
model.Log.Errorf("MicChangeRPush getMicUserDatas id:%v noexit", id)
}
vipTime, vipFlag := vipMap[id]
if vipTime == nil {
vipFlag = false
}
var headwearPicUrl string
var headwearEffectUrl string
if headwearUser, flag := headwearMap[id]; flag {
headwearPicUrl = resHeadwearMap[headwearUser.HeadwearId].PicUrl
headwearEffectUrl = resHeadwearMap[headwearUser.HeadwearId].EffectUrl
}
micUserDataMap[id] = &MicUserData{
Id: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
IsVip: vipFlag,
NobleLeave: nobleMap[id],
HeadwearPicUrl: headwearPicUrl,
HeadwearEffectUrl: headwearEffectUrl,
SvipLevel: svips[id].SvipLevel,
Svip: rpc.CopySimpleSvip(svips[id]),
}
}
return micUserDataMap, nil
}
func getMicUserData(model *domain.Model, userId uint64) (*MicUserData, error) {
user, err := user_m.GetUser(model, userId)
if err != nil {
return nil, err
}
flag, _, err := user_m.IsVip(userId)
if err != nil {
return nil, err
}
nobleLeave, err := noble_m.GetNobleLevel(model.Db, userId)
if err != nil {
return nil, err
}
svip, _ := rpc.GetUserSvip(model, userId)
var headwearPicUrl string
var headwearEffectUrl string
headwear, err := user_m.GetUserHeadwearUsing(model, userId)
if err != nil {
return nil, err
}
if headwear != nil {
resHeadwear, err := res_m.GetHeadwearById(model, headwear.HeadwearId)
if err != nil {
return nil, err
}
headwearPicUrl = resHeadwear.PicUrl
headwearEffectUrl = resHeadwear.EffectUrl
}
return &MicUserData{
Id: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
IsVip: flag,
NobleLeave: nobleLeave,
HeadwearPicUrl: headwearPicUrl,
HeadwearEffectUrl: headwearEffectUrl,
SvipLevel: svip.SvipLevel,
Svip: rpc.CopySimpleSvip(svip),
}, nil
}
package group_m
import (
"fmt"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/myerr"
"time"
)
type GroupMicInLog struct {
mysql.Entity
UserId mysql.ID
GroupId mysql.Str
}
func (p *GroupMicInLog) TableName() string {
month := time.Now().Format("200601")
return fmt.Sprintf("group_mic_in_log_%s", month)
}
func AddGroupMicInLog(userId mysql.ID, groupId mysql.Str) error {
if err := mysql.Db.Table((&GroupMicInLog{}).TableName()).Create(&GroupMicInLog{
Entity: mysql.Entity{},
UserId: userId,
GroupId: groupId,
}).Error; err != nil {
mylogrus.MyLog.Errorf("GroupMicInLog save fail, err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
package group_m
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"hilo-group/_const/enum/group_e"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/user_m"
"runtime/debug"
"time"
)
//公屏消息
type PublicScreenMsg struct {
Code uint8
Data map[string]string
}
// 信令消息
type GroupSystemMsg struct {
MsgId group_e.TypeSignalMsg `json:"msgId"`
Source string `json:"source"`
Target string `json:"target"`
Content string `json:"content"`
}
type UserJoinPublicMsg struct {
Type uint8 `json:"type"`
ExternalId string `json:"externalId"`
Nick string `json:"nick"`
}
type CommonPublicMsg struct {
Type uint8 `json:"type"`
OperatorExternalId string `json:"operatorExternalId"`
OperatorNick string `json:"operatorNick"`
OperatorAvatar string `json:"operatorAvatar"`
ExternalId string `json:"externalId"`
Nick string `json:"nick"`
Avatar string `json:"avatar"`
IsVip bool `json:"is_vip"`
Role uint16 `json:"role"`
NobleLevel uint16 `json:"nobleLevel"`
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
}
type RollDiceMsg struct {
CommonPublicMsg
Dices []int `json:"dices"`
}
type GroupSupportH5 struct {
CommonPublicMsg
H5 string `json:"h5"`
}
type RocketAwardMsg struct {
CommonPublicMsg
AwardType uint16 `json:"awardType"` // 奖励类型
Number uint32 `json:"number"` // 数量(天/个数)
}
type LuckyboxAwardMsg struct {
CommonPublicMsg
Number uint32 `json:"number"` //前端要求,含义钻石数量
}
type FruitMachineAwardMsg struct {
CommonPublicMsg
DiamondNum uint `json:"diamondNum"`
}
type GroupCustomMsgContentType = int
const (
// 跳转url
GroupCustomMsgH5 GroupCustomMsgContentType = 1
// 跳转房间
GroupCustomMsgJump GroupCustomMsgContentType = 2
//
)
type GroupCustomMsg struct {
CommonPublicMsg
ContentType int `json:"contentType"`
Content string `json:"content"`
H5 string `json:"h5"`
GroupId string `json:"groupId"`
}
//
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"`
}
//不用返回错误
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 ""
}
hilo := HiloUserInfo{
WealthGrade: wealthGrade,
CharmGrade: charmGrade,
IsVip: isVip,
IsPretty: isPretty,
Medals: medals,
PowerName: powerName,
NobleLevel: nobleLevel,
}
buf, err := json.Marshal(hilo)
if err != nil {
model.Log.Errorf("hilo:%+v, err:%v", hilo, err)
}
return string(buf)
}
//
var GetGroupPowerNameByUserId func(model *domain.Model, userId uint64) (uint64, string, error)
// 多协程并行发送群消息
func BroadcastGroupMessage(model *domain.Model, groupIds []string, content string, hiloUserInfo string) {
n := config.GetGroupImConfig().MSG_PARALLEL_SIZE
if n <= 0 {
n = group_e.DefaultMsgParallelSize
}
buckets := make([][]string, n, n)
for i := 0; i < n; i++ {
buckets[i] = make([]string, 0)
}
for i := 0; i < len(groupIds); i++ {
buckets[i%n] = append(buckets[i%n], groupIds[i])
}
model.Log.Infof("%d groups split into %d buckets", len(groupIds), n)
for i, _ := range buckets {
go func(model *domain.Model, bucketId int, groupIds []string, content string) {
defer func() {
if r := recover(); r != nil {
model.Log.Errorf("BroadcastGroupMessage SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
for j, g := range groupIds {
txGroupId, err := ToTxGroupId(model, g)
if err == nil {
model.Log.Infof("Bucket %d, sending message to groupId %d: %s", bucketId, j, txGroupId)
tencentyun.SendCustomMsg(model.Log, txGroupId, nil, content, hiloUserInfo)
}
if j%10 == 0 {
time.Sleep(time.Second)
}
}
}(domain.CreateModelContext(model.MyContext), i, buckets[i], content)
}
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/myerr"
)
func AddGroupKickRecord(model *domain.Model, imGroupId string, userId mysql.ID, beKickUserId mysql.ID) error {
groupKickRecord := GroupKickRecord{
Model: model,
ImGroupId: imGroupId,
UserId: userId,
BeKickUserId: beKickUserId,
}
if err := model.Db.Create(&groupKickRecord).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
package group_m
import (
"context"
"git.hilo.cn/hilo-common/resource/redisCli"
redis2 "github.com/go-redis/redis/v8"
"hilo-group/_const/redis_key"
"hilo-group/domain/model"
"hilo-group/myerr"
)
func (groupMsg *GroupMsg) Persistent() error {
if err := model.Persistent(groupMsg.Db, groupMsg); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupUser *GroupUser) Persistent() error {
if err := model.Persistent(groupUser.Db, groupUser); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (rediGroupMsgSeqMax *RediGroupMsgSeqMax) Persistent() error {
if err := redisCli.GetRedis().HSet(context.Background(), redis_key.GetPrefixGroupMsgSeqMaxAll(), rediGroupMsgSeqMax.GroupUuid, rediGroupMsgSeqMax.Seq).Err(); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (redisGroupMsgSeqMaxUser *RedisGroupMsgSeqMaxUser) Persistent() error {
if err := redisCli.GetRedis().HSet(context.Background(), redis_key.GetPrefixGroupMsgSeqMaxGroup(redisGroupMsgSeqMaxUser.GroupUuid), redisGroupMsgSeqMaxUser.GroupUuid+"_"+redisGroupMsgSeqMaxUser.ExternalId, redisGroupMsgSeqMaxUser.Seq).Err(); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (redisGroupMsgDurationScore *RedisGroupMsgDurationScore) Persistent() error {
if redisGroupMsgDurationScore.AddCountUser != 0 {
if err := redisCli.GetRedis().ZIncrBy(context.Background(), redis_key.GetPrefixGroupMsgDurationScore(), float64(redisGroupMsgDurationScore.AddCountUser), redisGroupMsgDurationScore.GroupUuid).Err(); err != nil {
return err
}
}
return nil
}
func (redisGroupUserMsgDuration *RedisGroupMsgDurationUser) Persistent() (int64, error) {
if i, err := redisCli.GetRedis().ZAdd(context.Background(), redis_key.GetPrefixGroupMsgDurationUser(), &redis2.Z{
Score: float64(redisGroupUserMsgDuration.TimeStamp),
Member: redisGroupUserMsgDuration.GroupUuid + "_" + redisGroupUserMsgDuration.ExternalId,
}).Result(); err != nil {
return i, err
} else {
return i, nil
}
}
func (groupSupportAwardAdmin *GroupSupportAwardAdmin) Persistent() error {
if err := model.Persistent(groupSupportAwardAdmin.Db, groupSupportAwardAdmin); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupSupportAwardMgr *GroupSupportAwardMgr) Persistent() error {
if err := model.Persistent(groupSupportAwardMgr.Db, groupSupportAwardMgr); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupSupportResult *GroupSupportResult) Persistent() error {
if err := model.Persistent(groupSupportResult.Db, groupSupportResult); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupCustomTheme *GroupCustomTheme) Persistent() error {
if err := model.Persistent(groupCustomTheme.Db, groupCustomTheme); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (groupMedal *GroupMedal) Persistent() error {
if err := model.Persistent(groupMedal.Db, groupMedal); err != nil {
return myerr.WrapErr(err)
}
return nil
}
//func (micUser *MicUser) Persistent() error {
// //map 结构 key:groupUuid key:i value:123_0
// if micUser.UserId == nil {
// //下麦
// //redis + lua 集成多个命令来保证原子性 或者 用 Multi EXEC ,先用Multi找出该麦位上是否有这个用户,然后再下麦。
// pipeliner := redisCli.GetRedis().TxPipeline()
// redisUserId, err := pipeliner.HGet(context.Background(), redis.GetPrefixGroupMicGroupUuid(micUser.GroupUuid), strconv.Itoa(micUser.I)).Result()
// if err != nil {
// //已经不存在,则抛出错误
// if err == redis2.Nil {
// return nil
// } else{
// return myerr.WrapErr(err)
// }
// }
// //不等于自己
// if redisUserId != strconv.Itoa(int(micUser.operateUser)) {
// return
// }
// redisCli.GetRedis().pipe := client.TxPipeline()
// } else {
// //上卖 同 禁言操作,注意
// //上麦 HsetNx
// //禁言 Multi EXEC ,先用Multi找出该麦位上是否有这个用户,然后再修改状态。。
// redisCli.GetRedis().HSetNX(context.Background(), redis.GetPrefixGroupMicGroupUuid(micUser.GroupUuid), strconv.Itoa(micUser.I))
// }
//}
//func (mic *Mic) Persistent() error {
// b, err := json.Marshal(mic)
// if err != nil {
// return myerr.WrapErr(err)
// }
// _, err = redisCli.GetRedis().HSet(context.Background(), redis.GetPrefixGroupMicGroupUuid(mic.GroupUuid), strconv.Itoa(mic.I), b).Result()
// if err != nil {
// return myerr.WrapErr(err)
// }
//
// return nil
//}
package group_m
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
redis2 "github.com/go-redis/redis/v8"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/user_m"
"hilo-group/myerr"
"sort"
"strconv"
"strings"
"time"
)
/**
* redis记录。
sortSet记录房间中的人 (groupUid_userId),5分钟的http麦位信息轮询, 更新sortSet的分值(有效期),并且更新sortSet的过期时间
选择sortSet,而不是 key的原因:
1:扩展更多功能,在房间的人,房间内先入后到的排名(score的高低位)
2:通过sortSet的key的生命周期,一样能保证清理僵尸用户。
*/
func getMemberStr(groupUid string, userId uint64) string {
return groupUid + "_" + strconv.FormatUint(userId, 10)
}
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
}
func RoomLivingExpire(model *domain.Model, groupUid string, userId uint64) {
model.Log.Infof("room RoomLivingExpire userId:%v, groupUid:%v", userId, groupUid)
//
key := redis_key.GetPrefixGroupRoomLiving()
i, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{
Score: float64(time.Now().Unix()),
Member: getMemberStr(groupUid, userId),
}).Result()
if err != nil {
model.Log.Errorf("RoomLivingExpire ZAdd key:%v, groupUid:%v, userId:%v, err:%v", key, groupUid, userId, err)
} else {
model.Log.Infof("RoomLivingExpire ZAdd key:%v, groupUid:%v, userId:%v result:%v", key, groupUid, userId, i)
}
}
//进入房间
func RoomLivingIn(model *domain.Model, groupUid string, userId uint64, externalId string, robot bool) error {
model.Log.Infof("room RoomLivingIn userId:%v, groupUid:%v", userId, groupUid)
//这个可以考虑用go协程
if !robot {
RoomLivingLeave(model, userId, externalId, "")
}
//
key := redis_key.GetPrefixGroupRoomLiving()
i, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{
Score: float64(time.Now().Unix()),
Member: getMemberStr(groupUid, userId),
}).Result()
if err != nil {
model.Log.Errorf("UpdateRoomLiving ZAdd key:%v, groupUid:%v, userId:%v, err:%v", key, groupUid, userId, err)
} else {
model.Log.Infof("UpdateRoomLiving ZAdd key:%v, groupUid:%v, userId:%v result:%v", key, groupUid, userId, i)
}
go func(myContext *mycontext.MyContext, groupId string) {
roomOnlineUser, err := GetRoomOnlineUser(myContext, groupId)
if err != nil {
myContext.Log.Errorf("room RoomLivingIn roomOnlineUser err:%+v, groupUid:%v", err, groupId)
//错误,跳过,不退出
return
}
buf, err := json.Marshal(roomOnlineUser)
if err != nil {
myContext.Log.Errorf("room RoomLivingIn roomOnlineUser json.Marshal err:%+v groupUid:%v", err, groupId)
//错误,跳过,不退出
return
} else {
myContext.Log.Infof("room RoomLivingIn json.Marshal success groupUid:%v, data:%v", groupId, string(buf))
//发送在线
sendSignalMsg(model, groupId, GroupSystemMsg{
MsgId: group_e.GroupOnlineUser,
Content: string(buf),
}, true)
}
}(model.MyContext, groupUid)
return err
}
//离开房间
func roomLivingLeave(model *domain.Model, userId uint64, groupId string) ([]string, error) {
model.Log.Infof("RoomLivingLeave userId:%v", userId)
key := redis_key.GetPrefixGroupRoomLiving()
//if err := redisCli.ClearExpired(key, expireMinute); err != nil {
if err := model.Redis.ZRemRangeByScore(model, key, "0", strconv.FormatInt(time.Now().Unix()-expireMinute, 10)).Err(); err != nil {
return nil, myerr.WrapErr(err)
}
data, err := redisCli.GetRedis().ZRange(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
groupIds := make([]string, 0)
for i, _ := range data {
gid, uid := analysisMemberStr(data[i])
if uid == userId && (groupId == "" || gid == groupId) {
if _, err := redisCli.GetRedis().ZRem(context.Background(), key, getMemberStr(gid, uid)).Result(); err != nil {
model.Log.Errorf("RoomLivingLeave ZRem key:%s, groupId:%s, userId:%d, err:%v", key, gid, uid, err)
return nil, myerr.WrapErr(err)
} else {
groupIds = append(groupIds, gid)
model.Log.Infof("RoomLivingLeave ZRem success key:%s, groupId:%s, userId:%d", key, gid, uid)
}
// 发信令,让前端重新拉取,接受容错,
user, err := user_m.GetUser(model, userId)
if err != nil || user == nil {
model.Log.Errorf("RoomLivingLeave GetUser err:%v", err)
} else {
sendSignalMsg(model, gid, GroupSystemMsg{
MsgId: group_e.GroupOutSignal,
Source: user.ExternalId,
}, false)
}
}
}
go func(myContext *mycontext.MyContext, groupIds []string) {
for i, groupId := range groupIds {
roomOnlineUser, err := GetRoomOnlineUser(myContext, groupIds[i])
if err != nil {
myContext.Log.Errorf("RoomLivingLeave roomOnlineUser err:%+v, groupUid:%v", err, groupId)
//错误,跳过,不退出
continue
}
buf, err := json.Marshal(roomOnlineUser)
if err != nil {
myContext.Log.Errorf("RoomLivingLeave roomOnlineUser json.Marshal err:%+v groupUid:%v", err, groupId)
//错误,跳过,不退出
continue
} else {
myContext.Log.Infof("RoomLivingLeave json.Marshal success groupUid:%v, data:%v", groupId, string(buf))
//发送在线
sendSignalMsg(domain.CreateModelContext(myContext), groupId, GroupSystemMsg{
MsgId: group_e.GroupOnlineUser,
Content: string(buf),
}, true)
}
}
}(model.MyContext, groupIds)
return groupIds, nil
}
//离开房间
func RoomLivingLeave(model *domain.Model, userId uint64, externalId string, groupId string) ([]string, error) {
model.Log.Infof("RoomLivingLeave userId:%v", userId)
//获取用户是否在麦上, 让用户离开麦
micUser, err := GetMicUserByExternalId(model, externalId)
if err != nil {
return nil, err
}
if micUser != nil {
if err = micUser.LeaveByUser(userId, externalId); err != nil {
return nil, err
}
}
return roomLivingLeave(model, userId, groupId)
}
//被踢出离开房间
func RoomLivingLeaveByKick(model *domain.Model, groupUuid string, beKickuserId uint64, beKickExternalId string, userExternalId string) ([]string, error) {
model.Log.Infof("RoomLivingLeaveByKick userId:%v", beKickuserId)
//获取用户是否在麦上, 让用户离开麦
micUser, err := GetMicUserByExternalId(model, beKickExternalId)
if err != nil {
return nil, err
}
if micUser != nil {
if err = micUser.LeaveByUser(beKickuserId, beKickExternalId); err != nil {
return nil, err
}
}
// 发信令,让前端重新拉取,接受容错,
/* sendSignalMsg(model, groupUuid, GroupSystemMsg{
MsgId: group_enum.GroupKickOut,
Source: userExternalId,
Target: beKickExternalId,
}, false)*/
MicGroupKickOutRPush(model, groupUuid, userExternalId, beKickExternalId)
return roomLivingLeave(model, beKickuserId, groupUuid)
}
// 直播群状态回调导致的下麦
func RoomLivingLeaveByOffline(model *domain.Model, userId uint64, externalId string, groupId string) ([]string, error) {
//获取用户是否在麦上, 让用户离开麦
micUser, err := GetMicUserByExternalId(model, externalId)
if err != nil {
return nil, err
}
if micUser != nil {
model.Log.Infof("RoomLivingLeaveByOffline user %d, %s, groupId:%s", userId, externalId, groupId)
if err = micUser.LeaveByUser(userId, externalId); err != nil {
return nil, err
}
MicSocketMicOutRPush(model, micUser.GroupUuid, micUser.ExternalId)
}
return roomLivingLeave(model, userId, groupId)
}
//socket掉线被提出
func RoomLivingLeaveByMgr(model *domain.Model, userId uint64, externalId string, groupId string) ([]string, error) {
model.Log.Infof("RoomLivingLeaveByMgr userId:%v", userId)
//获取用户是否在麦上, 让用户离开麦
micUser, err := GetMicUserByExternalId(model, externalId)
if err != nil {
return nil, err
}
if micUser != nil {
if err = micUser.LeaveByUser(userId, externalId); err != nil {
return nil, err
}
MicSocketMicOutRPush(model, micUser.GroupUuid, micUser.ExternalId)
}
groupIds, err := roomLivingLeave(model, userId, groupId)
if err != nil {
return groupIds, err
}
// 发送信令
type removeHistoryParam struct {
RemoveHistory bool `json:"removeHistory"`
}
r := removeHistoryParam{RemoveHistory: true}
buf, err := json.Marshal(r)
if err == nil {
systemMsg := GroupSystemMsg{MsgId: group_e.GroupMemberRemoveSignal,
Target: externalId, Content: string(buf)}
for i, _ := range groupIds {
sendSignalMsg(model, groupIds[i], systemMsg, false)
}
}
return groupIds, err
}
//获取在房间的用户(其中成员的位置按分数值递增(从大到小)来排序)
func RoomLivingExistsUserId(groupUid string) ([]uint64, error) {
key := redis_key.GetPrefixGroupRoomLiving()
//if err := redisCli.ClearExpired(key, expireMinute); err != nil {
var model = domain.CreateModelNil()
if err := model.Redis.ZRemRangeByScore(model, key, "0", strconv.FormatInt(time.Now().Unix()-expireMinute, 10)).Err(); err != nil {
return nil, myerr.WrapErr(err)
}
groupUserIdstrs, err := redisCli.GetRedis().ZRevRange(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
mylogrus.MyLog.Infof("group_room_living RoomLivingExistsUserId groupUserIdstrs:%v", groupUserIdstrs)
userIds := make([]uint64, 0, len(groupUserIdstrs))
for i, _ := range groupUserIdstrs {
tempGroupUid, userId := analysisMemberStr(groupUserIdstrs[i])
if tempGroupUid == groupUid {
userIds = append(userIds, userId)
}
}
return userIds, nil
}
//获取在房间的用户 返回值:map,key:userId, value:groupUuid
func RoomLivingUserIdFilter(userIds []mysql.ID) (map[mysql.ID]string, error) {
userIdSet := map[mysql.ID]struct{}{}
for i, _ := range userIds {
userIdSet[userIds[i]] = struct{}{}
}
key := redis_key.GetPrefixGroupRoomLiving()
//if err := redisCli.ClearExpired(key, expireMinute); err != nil {
model := domain.CreateModelNil()
if err := model.Redis.ZRemRangeByScore(model, key, "0", strconv.FormatInt(time.Now().Unix()-expireMinute, 10)).Err(); err != nil {
return nil, myerr.WrapErr(err)
}
groupUserIdstrs, err := redisCli.GetRedis().ZRange(context.Background(), 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])
mylogrus.MyLog.Debugf("RoomLivingUserIdFilter, analysisMemberStr %s, %d", tempGroupUid, userId)
if _, flag := userIdSet[userId]; flag {
resultUserSet[userId] = tempGroupUid
}
}
return resultUserSet, nil
}
//获取有人的房间, 返回值:Map[groupUid]Set<UserId>
func RoomLivingExistsGroup(model *domain.Model) (map[string]map[uint64]struct{}, error) {
key := redis_key.GetPrefixGroupRoomLiving()
//if err := redisCli.ClearExpired(key, expireMinute); err != nil {
if err := model.Redis.ZRemRangeByScore(model, key, "0", strconv.FormatInt(time.Now().Unix()-expireMinute, 10)).Err(); err != nil {
model.Log.Infof("RoomLivingExistsGroup: err:%v", err)
return nil, myerr.WrapErr(err)
}
groupUserIdstrs, err := redisCli.GetRedis().ZRange(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, myerr.WrapErr(err)
}
model.Log.Infof("group_room_living RoomLivingExistsGroup groupUserIdstrs:%v", groupUserIdstrs)
groupGroup := map[string]map[uint64]struct{}{}
for i, _ := range groupUserIdstrs {
tempGroupUid, userId := analysisMemberStr(groupUserIdstrs[i])
if a, flag := groupGroup[tempGroupUid]; flag {
a[userId] = struct{}{}
} else {
groupGroup[tempGroupUid] = map[uint64]struct{}{userId: {}}
}
}
model.Log.Infof("RoomLivingExistsGroup size = %d", len(groupGroup))
return groupGroup, nil
}
func BatchGetRoomCount(model *domain.Model, groupIds []string) (map[string]int, error) {
liveRoom, err := RoomLivingExistsGroup(model)
if err != nil {
return nil, err
}
result := make(map[string]int, 0)
for _, i := range groupIds {
result[i] = len(liveRoom[i])
}
return result, nil
}
// 取所有有人的房间,以房间人数排序
func GetAllGroupsSorted(model *domain.Model) ([]string, error) {
// 1. 当前有人的房间
liveRoom, err := RoomLivingExistsGroup(model)
if err != nil {
model.Log.Infof("GetAllGroupsSorted: err:%v", err)
return nil, err
}
roomCount := make(map[string]int, 0)
for k, i := range liveRoom {
roomCount[k] = len(i)
}
model.Log.Infof("GetAllGroupsSorted, living room : %v", roomCount)
groupIds := make([]string, 0)
for k, _ := range liveRoom {
groupIds = append(groupIds, k)
}
sort.Slice(groupIds, func(i, j int) bool {
gi := groupIds[i]
gj := groupIds[j]
return roomCount[gi] > roomCount[gj] || roomCount[gi] == roomCount[gj] && gi < gj
})
return groupIds, nil
}
// 取房间最近N天的访问人数
func GetRoomVisitCount(groupId string) (int64, error) {
// 每群定时请一次数据可以了
now := time.Now()
if now.Second()%redis_key.GroupInDurationClearPeriod == 0 {
// 先移除(N天之前的),后统计
if _, err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetPrefixGroupInUserDuration(groupId),
"0", strconv.FormatInt(time.Now().AddDate(0, 0, -redis_key.GroupInDurationTTL).Unix(), 10)).
Result(); err != nil {
return 0, err
}
}
visitCount, err := redisCli.GetRedis().ZCard(context.Background(), redis_key.GetPrefixGroupInUserDuration(groupId)).Result()
if err != nil {
return 0, err
}
return visitCount, nil
}
// 批量查询房间的麦位 TODO: 优化性能
func GetRoomMicUsers(model *domain.Model, groupIds []string) (map[string][]uint64, error) {
result := make(map[string][]uint64, 0)
for _, g := range groupIds {
userIds, err := GetAllMicUser(g)
if err != nil {
model.Log.Warnf("GetRoomMicUsers, GetAllMicUser: groupId %s err %s", g, err.Error())
} else {
result[g] = userIds
}
}
return result, nil
}
// 批量查询房间最近N天的访问人数。使用二级缓存
func BatchGetRoomVisitCount(logE *logrus.Entry, groupIds []string) (map[string]int64, error) {
//roomVisitCount, err := redis.GetAllRoomVisitCount()
roomVisitCount, err := room_c.MGetRoomVisitCount(groupIds)
if err != nil {
return nil, err
}
logE.Infof("MGetRoomVisitCount:%v", roomVisitCount)
visitCount := make(map[string]int64)
for _, groupId := range groupIds {
// 先从二级缓存中找
if c, ok := roomVisitCount[groupId]; ok {
if vc, err := strconv.ParseInt(c, 10, 64); err == nil && vc > 0 {
logE.Debugf("GetRoomVisitCount, from roomVisitCount %s - %d", groupId, vc)
visitCount[groupId] = vc
}
} else {
// 如果没有,就从roomVisit中取
if vc, err := room_c.GetSetRoomVisitCount(groupId); err == nil && vc > 0 {
logE.Infof("GetRoomVisitCount, from roomVisit %s - %d", groupId, vc)
visitCount[groupId] = vc
}
}
}
return visitCount, nil
}
type UserEnterRoom struct {
UserId uint64
GroupId string
EnterTime time.Time
}
func (uer *UserEnterRoom) save(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{UpdateAll: true}).Create(uer).Error
}
func (uer *UserEnterRoom) Find(db *gorm.DB) ([]UserEnterRoom, error) {
rows := make([]UserEnterRoom, 0)
if err := db.Where(uer).Order("enter_time DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
type RoomMonthConsume struct {
GroupId string
Month string
Diamond uint64
}
func (rmc *RoomMonthConsume) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"diamond": gorm.Expr("diamond + ?", rmc.Diamond)}),
}).Create(rmc).Error
}
func (rmc *RoomMonthConsume) GetTotalDiamond(db *gorm.DB) (uint64, error) {
rows := make([]struct{ Total uint64 }, 0)
if err := db.Model(&RoomMonthConsume{}).Select("SUM(diamond) AS total").
Where(rmc).Find(&rows).Error; err != nil {
return 0, err
}
if len(rows) > 0 {
return rows[0].Total, nil
}
return 0, nil
}
type RoomWeekConsume struct {
GroupId string
Week string
Diamond uint64
}
func (rwc *RoomWeekConsume) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"diamond": gorm.Expr("diamond + ?", rwc.Diamond)}),
}).Create(rwc).Error
}
type RoomDayConsume struct {
GroupId string
Day string
Diamond uint64
}
func (rdc *RoomDayConsume) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"diamond": gorm.Expr("diamond + ?", rdc.Diamond)}),
}).Create(rdc).Error
}
type RoomUserDayConsume struct {
Day string
GroupId string
SendUserId uint64
Diamond uint64
}
func (rudc *RoomUserDayConsume) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"diamond": gorm.Expr("diamond + ?", rudc.Diamond)}),
}).Create(rudc).Error
}
// todo todo 这里可能需要!!!
//func init() {
// event.AddGroupInAsync(func(model *domain.Model, e interface{}) error {
// event := e.(*event.GroupInEvent)
// model.Log.Infof("AddGroupInAsync for room: %+v", event)
//
// uer := UserEnterRoom{
// UserId: event.UserId,
// GroupId: event.GroupId,
// EnterTime: time.Now(),
// }
// err := uer.save(model.Db)
// model.Log.Infof("AddGroupInAsync, UserEnterRoom err: %v", err)
// return err
// })
//
// event.AddSendGift(func(model *domain.Model, event *event.SendGiftEvent) error {
// if event.NoExecSync {
// model.Log.Infof("Skip %+v", event)
// return nil
// }
// model.Log.Infof("AddSendGift room: %+v", event)
//
// // 群消费月表涉及总消费额,需要在同步处理中,但不报错
// if event.ResGift.GiftType == mysql.DiamondYellow && event.SceneType == gift_m2.GroupSceneType && len(event.SceneUid) > 0 {
// now := time.Now()
// rmc := RoomMonthConsume{
// GroupId: event.SceneUid,
// Month: now.Format(common.COMPACT_MONTH_FORMAT),
// Diamond: event.GetDiamondTotal(),
// }
// err := rmc.AddDiamond(model.Db)
// if err != nil {
// model.Log.Infof("AddSendGiftAsync room, %+v AddDiamond failed: %v", rmc, err)
// } else {
// // 增加后在事务中读出来,供异步事件中使用
// rmc = RoomMonthConsume{GroupId: event.SceneUid}
// if consume, err := rmc.GetTotalDiamond(model.Db); err == nil {
// event.TotalConsume = consume
// }
// }
// }
// return nil
// })
//
// event.AddSendGiftAsync(func(model *domain.Model, event *event.SendGiftEvent) error {
// model.Log.Infof("AddSendGiftAsync room: %+v", event)
//
// if event.SceneType == gift_m2.GroupSceneType && len(event.SceneUid) > 0 {
// now := time.Now()
// rwc := RoomWeekConsume{
// GroupId: event.SceneUid,
// Week: common.GetMonday(now).Format(common.DATE_FORMAT),
// Diamond: event.GetDiamondTotal(),
// }
// err := rwc.AddDiamond(model.Db)
// if err != nil {
// model.Log.Infof("AddSendGiftAsync room, %+v AddDiamond failed: %v", rwc, err)
// }
//
// rdc := RoomDayConsume{
// GroupId: event.SceneUid,
// Day: now.Format(common.DATE_FORMAT),
// Diamond: event.GetDiamondTotal(),
// }
// err = rdc.AddDiamond(model.Db)
// if err != nil {
// model.Log.Infof("AddSendGiftAsync room, %+v AddDiamond failed: %v", rdc, err)
// }
//
// err = redis.ClearGroupConsume(event.SceneUid)
// if err != nil {
// model.Log.Infof("AddSendGiftAsync room, group %s redis.ClearGroupConsume failed: %v", event.SceneUid, err)
// }
// }
// return nil
// })
//
// event.AddSendGiftAsync(func(model *domain.Model, event *event.SendGiftEvent) error {
// model.Log.Infof("AddSendGiftAsync roomUserDay: %+v", event)
//
// if event.SceneType == gift_m2.GroupSceneType && len(event.SceneUid) > 0 {
// now := time.Now()
// rudc := RoomUserDayConsume{
// Day: now.Format(common.DATE_FORMAT),
// GroupId: event.SceneUid,
// SendUserId: event.SendUserId,
// Diamond: event.GetDiamondTotal(),
// }
// err := rudc.AddDiamond(model.Db)
// if err != nil {
// model.Log.Infof("AddSendGiftAsync roomUserDay, %+v AddDiamond failed: %v", rudc, err)
// }
// return err
// }
// return nil
// })
//
// event.AddUserFreezeAsync(func(model *domain.Model, event *event.UserFreezeEvent) error {
// model.Log.Infof("AddUserFreezeAsync room: %+v", event)
// user, err := user_m.GetUser(model, event.UserId)
// if err != nil {
// return err
// }
// if _, err := RoomLivingLeaveByMgr(model, user.ID, user.ExternalId, ""); err != nil {
// model.Log.Errorf("AddUserFreezeAsync room err:%v", err)
// }
//
// // 连带重置群信息
// if gi, err := FindGroupByOwner(model, event.UserId); err == nil && len(gi) > 0 {
// if err = ResetGroupInfo(model, gi[0].ImGroupId, gi[0].Code); err != nil {
// model.Log.Warnf("ResetGroupInfo user %d's group %s failed", event.UserId, gi[0].ImGroupId)
// }
// }
// return nil
// })
//
//}
package group_m
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"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/user_m"
"sort"
"time"
)
type RoomOnlineUser struct {
Total int `json:"total"`
Users []RoomOnlineUserMsg `json:"users"`
//客户端对比,只要
ServiceTime int64 `json:"serviceTime"`
}
type RoomOnlineUserMsg 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:没有注销
//是否VIP用户
IsVip bool `json:"isVip"`
//贵族
Noble RoomUserNoble `json:"noble"` // 当前的
//VIP用户过期时间(只有自己查询自己,才返回)
VipExpireTime *int64 `json:"vipExpireTime"`
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
}
type RoomUserNoble struct {
Level uint16 `json:"level"`
EndTime int64 `json:"endTime"`
}
func GetRoomOnlineUser(cxt *mycontext.MyContext, groupId string) (RoomOnlineUser, error) {
userIds, total, err := getGroupInUserIds(cxt, groupId)
if err != nil {
return RoomOnlineUser{}, err
}
var model = domain.CreateModelContext(cxt)
userMap, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return RoomOnlineUser{}, err
}
vipMap, err := user_m.BatchGetVips(userIds)
if err != nil {
return RoomOnlineUser{}, err
}
nobleMap, err := noble_m.BatchGetNobleLevel(mysql.Db, userIds)
if err != nil {
return RoomOnlineUser{}, err
}
svip, _ := rpc.MGetUserSvip(model, userIds)
users := make([]RoomOnlineUserMsg, 0, len(userIds))
for i := range userIds {
user, _ := userMap[userIds[i]]
users = append(users, RoomOnlineUserMsg{
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.Code != user.OriginCode,
IsLogout: false,
IsVip: vipMap[userIds[i]] != nil,
Noble: RoomUserNoble{
Level: nobleMap[userIds[i]],
EndTime: 0,
},
VipExpireTime: vipMap[userIds[i]],
SvipLevel: svip[userIds[i]].SvipLevel,
Svip: rpc.CopySimpleSvip(svip[userIds[i]]),
})
}
return RoomOnlineUser{
Total: total,
Users: users,
ServiceTime: time.Now().UnixNano(),
}, nil
}
var groupOnlineUserIdMaxNum int = 15
//显示的最大数量是15个。
func getGroupInUserIds(cxt *mycontext.MyContext, groupId string) ([]uint64, int, error) {
userIds, err := RoomLivingExistsUserId(groupId)
if err != nil {
return []uint64{}, 0, err
}
if len(userIds) == 0 {
return []uint64{}, 0, nil
}
var model = domain.CreateModelContext(cxt)
svips, err := rpc.MGetUserSvip(model, userIds)
if err != nil {
model.Log.Errorf("MGetUserSvip fail :%v", err)
}
//贵族
nobleLevelMap, err := noble_m.BatchGetNobleLevel(mysql.Db, userIds)
if err != nil {
model.Log.Errorf("BatchGetNobleLevel fail :%v", err)
}
//获取vip
vipMap, err := user_m.BatchGetVips(userIds)
if err != nil {
model.Log.Errorf("MGetUserSvip fail :%v", err)
}
// svip > noble > vip
sort.Slice(userIds, func(i, j int) bool {
if svips[userIds[i]].SvipLevel > svips[userIds[j]].SvipLevel {
return true
} else if svips[userIds[i]].SvipLevel == svips[userIds[j]].SvipLevel {
if nobleLevelMap[userIds[i]] > nobleLevelMap[userIds[j]] {
return true
} else if nobleLevelMap[userIds[i]] == nobleLevelMap[userIds[j]] {
var vi, vj int64
if ts, ok := vipMap[userIds[i]]; ok && ts != nil {
vi = *ts
}
if ts, ok := vipMap[userIds[j]]; ok && ts != nil {
vj = *ts
}
return vi > vj
}
}
return false
})
total := len(userIds)
if total > groupOnlineUserIdMaxNum {
return userIds[0:groupOnlineUserIdMaxNum], total, nil
}
return userIds, total, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/res_e"
"hilo-group/domain/model/res_m"
"hilo-group/myerr"
"time"
)
type GroupSupportResult struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
Grade res_e.ResGroupSupportGrade
Period mysql.Str
Heat uint // 群热度
}
// 根据指定时间计算支持度时间范围:时间到上一个周一的沙特18PM,即北京时间23PM 到 下一个周一同样时间
func GetSupportLevelTime(t time.Time) (time.Time, time.Time, string) {
t = utils.GetMonday(t)
beginTime := time.Date(t.Year(), t.Month(), t.Day(), group_e.SUPPORT_LEVEL_BOUNDARY_HOUR, 0, 0, 0, time.Local)
endTime := beginTime.AddDate(0, 0, group_e.SUPPORT_LEVEL_PERIOD_DAY)
return beginTime, endTime, endTime.Format(utils.DATE_FORMAT)
}
func InitGroupSupportResult(model *domain.Model, groupUid string, grade res_e.ResGroupSupportGrade, period string, heat uint) *GroupSupportResult {
return &GroupSupportResult{
Model: model,
GroupUid: groupUid,
Grade: grade,
Period: period,
Heat: heat,
}
}
func GetAllGroupSupportResult(db *gorm.DB, period string) (map[string]uint8, error) {
if len(period) <= 0 {
return nil, nil
}
gsr := GroupSupportResult{
Period: period,
}
rows := make([]GroupSupportResult, 0)
if err := db.Where(gsr).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[string]uint8)
for _, i := range rows {
result[i.GroupUid] = i.Grade
}
return result, nil
}
//群组扶持奖励,利益分配者
type GroupSupportAwardAdmin struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
IssuerUserId mysql.ID
UserId mysql.ID
DiamondNum mysql.Num
Grade res_e.ResGroupSupportGrade
ResGroupSupportId mysql.ID
Period mysql.Str
}
func (gsa *GroupSupportAwardAdmin) Get(db *gorm.DB) ([]GroupSupportAwardAdmin, error) {
result := make([]GroupSupportAwardAdmin, 0)
err := db.Model(&GroupSupportAwardAdmin{}).Where("group_uid = ? AND period >= ?", gsa.GroupUid, gsa.Period).Find(&result).Error
if err != nil {
return nil, err
}
return result, nil
}
//群组扶持奖励,助手
type GroupSupportAwardMgr struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
IssuerUserId mysql.ID
UserId mysql.ID
DiamondNum mysql.Num
Grade res_e.ResGroupSupportGrade
ResGroupSupportId mysql.ID
Period mysql.Str
}
func (gsa *GroupSupportAwardMgr) Get(db *gorm.DB) ([]GroupSupportAwardMgr, error) {
result := make([]GroupSupportAwardMgr, 0)
err := db.Model(&GroupSupportAwardMgr{}).Where("period >= ?", gsa.Period).Find(&result).Error
if err != nil {
return nil, err
}
return result, nil
}
//添加记录
func AddGroupSupportAward(model *domain.Model, groupUid string, issuerUserId mysql.ID, resGroupSupportId mysql.ID, userIds []mysql.ID, period string) (*GroupSupportAwardAdmin, []GroupSupportAwardMgr, error) {
//资源获取
resGroupSupport, err := res_m.GetResGroupSupportById(model, resGroupSupportId)
if err != nil {
return nil, nil, err
}
if int(resGroupSupport.MgrNum) < len(userIds) {
return nil, nil, myerr.NewSysErrorF("AddGroupSupportAward mgrNum:%v 同 len(userIds)=%v 不一致", resGroupSupport.MgrNum, len(userIds))
}
//增加群主奖励
groupSupportAwardAdmin := GroupSupportAwardAdmin{
Model: model,
GroupUid: groupUid,
IssuerUserId: issuerUserId,
UserId: issuerUserId,
DiamondNum: resGroupSupport.AdminAward,
Grade: resGroupSupport.Grade,
ResGroupSupportId: resGroupSupport.ID,
Period: period,
}
groupSupportAwardMgrs := make([]GroupSupportAwardMgr, 0, len(userIds))
//增加管理人奖励
for i, _ := range userIds {
groupSupportAwardMgrs = append(groupSupportAwardMgrs, GroupSupportAwardMgr{
Model: model,
GroupUid: groupUid,
IssuerUserId: issuerUserId,
UserId: userIds[i],
DiamondNum: resGroupSupport.MgrAward,
Grade: resGroupSupport.Grade,
ResGroupSupportId: resGroupSupport.ID,
Period: period,
})
}
return &groupSupportAwardAdmin, groupSupportAwardMgrs, nil
}
package luckyWheel_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/luckyWheel_e"
"time"
)
type LuckyWheel struct {
mysql.Entity
GroupId string
Creator uint64
CreatorJoin bool
EntranceFee uint32
AutoRestart bool
PlayerNum uint
PlayTime time.Time
NextTime time.Time
Status uint8
}
func (lw *LuckyWheel) Create(db *gorm.DB) error {
return db.Create(lw).Error
}
func (lw *LuckyWheel) Get(db *gorm.DB) error {
return db.Where(lw).First(lw).Error
}
func (lw *LuckyWheel) Remove(db *gorm.DB) (int64, error) {
result := db.Where(lw).Delete(&LuckyWheel{})
return result.RowsAffected, result.Error
}
func (lw *LuckyWheel) SetStatus(db *gorm.DB, status luckyWheel_e.LuckyWheelStatusType) error {
if status == luckyWheel_e.ROLLING {
return db.Model(&LuckyWheel{}).Where(lw).Updates(LuckyWheel{PlayTime: time.Now(), Status: status}).Error
} else {
return db.Model(&LuckyWheel{}).Where(lw).Update("status", status).Error
}
}
func (lw *LuckyWheel) AddPlayNum(db *gorm.DB) (int64, error) {
result := db.Model(&LuckyWheel{}).Where(lw).Update("player_num", gorm.Expr("player_num + 1"))
return result.RowsAffected, result.Error
}
func (lw *LuckyWheel) SetNextTime(db *gorm.DB, nexTime time.Time) error {
return db.Model(&LuckyWheel{}).Where(lw).Update("next_time", nexTime).Error
}
func GetTimeoutRecords(db *gorm.DB, status luckyWheel_e.LuckyWheelStatusType) ([]string, error) {
rows := make([]LuckyWheel, 0)
err := db.Where(&LuckyWheel{Status: status}).Where("next_time < now()").Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]string, 0)
for _, i := range rows {
result = append(result, i.GroupId)
}
return result, nil
}
func GetCronTimeoutRecords(db *gorm.DB) ([]string, []string, []string, []string, error) {
rows := make([]LuckyWheel, 0)
err := db.Model(&LuckyWheel{}).Where("next_time < now()").Find(&rows).Error
if err != nil {
return nil, nil, nil, nil, err
}
//result := make([]string, 0)
//for _, i := range rows {
// result = append(result, i.GroupId)
//}
//NONE LuckyWheelStatusType = 0 // 没有活动/已结束
//CREATED LuckyWheelStatusType = 1 // 创建,等待用户加入
//ROLLING LuckyWheelStatusType = 2 // 转动中
//SHOWING LuckyWheelStatusType = 3 // 结果展示中
//三种情况
timeOut := []string{} //过期退钱的
finish := []string{} //发钱的
showEnd := []string{} //下一个的
restart := []string{} // 需要创建新一轮的
for i, _ := range rows {
switch rows[i].Status {
case luckyWheel_e.CREATED:
timeOut = append(timeOut, rows[i].GroupId)
case luckyWheel_e.ROLLING:
finish = append(finish, rows[i].GroupId)
case luckyWheel_e.SHOWING:
showEnd = append(showEnd, rows[i].GroupId)
case luckyWheel_e.RESTARTING:
restart = append(restart, rows[i].GroupId)
}
}
return timeOut, finish, showEnd, restart, nil
}
// 计算转盘钻石结果
func CalcDiamond(entranceFee uint32, num int) (uint32, uint32) {
total := entranceFee * uint32(num)
winnerDiamnod := total * luckyWheel_e.LUCKY_WHEEL_WINNER_PERCENTILE / 100
ownerDiamnod := total * luckyWheel_e.LUCKY_WHEEL_OWNER_PERCENTILE / 100
return winnerDiamnod, ownerDiamnod
}
package luckyWheel_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type LuckyWheelHistory struct {
mysql.Entity
WheelId uint64
GroupId string
Creator uint64
EntranceFee uint32
PlayerNum uint
Winner uint64
WinnerAward uint32
GroupOwner uint64
GroupOwnerAward uint32
EndStatus uint8
}
func (lwh *LuckyWheelHistory) Create(db *gorm.DB) error {
return db.Create(lwh).Error
}
func (lwh *LuckyWheelHistory) Get(db *gorm.DB) error {
return db.Where(lwh).First(lwh).Error
}
package luckyWheel_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type LuckyWheelSeat struct {
mysql.Entity
WheelId uint64
GroupId string
SeatId uint
UserId uint64
SeqId uint
}
func (lws *LuckyWheelSeat) Create(db *gorm.DB) error {
return db.Create(lws).Error
}
func (lws *LuckyWheelSeat) Get(db *gorm.DB) ([]LuckyWheelSeat, error) {
result := make([]LuckyWheelSeat, 0)
if err := db.Where(lws).Find(&result).Error; err != nil {
return nil, err
}
return result, nil
}
func (lws *LuckyWheelSeat) SetSeqId(db *gorm.DB, seqId int) error {
return db.Model(LuckyWheelSeat{}).Where(lws).Update("seq_id", seqId).Error
}
package luckyWheel_m
import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type LuckyWheelUserOption struct {
UserId uint64
GroupId string
LastId uint
SelfJoin bool
AutoRestart bool
}
func (uo *LuckyWheelUserOption) Save(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"last_id", "self_join", "auto_restart"}),
}).Create(uo).Error
}
\ No newline at end of file
package luckybox_m
import (
"context"
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/utils"
redis2 "github.com/go-redis/redis/v8"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/luckybox_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model"
"hilo-group/myerr"
"math/rand"
"strconv"
"strings"
"time"
)
type LuckyboxCycleSum struct {
mysql.Entity
*domain.Model `gorm:"-"`
DiamondNum mysql.Num
UserId mysql.ID
Cycle mysql.Str
}
// 幸运盒子
type Luckybox struct {
mysql.Entity
*domain.Model `gorm:"-"`
DiamondNum mysql.Num
}
// 幸运盒子奖励
type LuckyboxAward struct {
mysql.Entity
*domain.Model `gorm:"-"`
//可能是id,也可能是diamondNum
AwardN uint64
AwardType luckybox_e.AwardTypeLuckyboxAward
PicUrl string
DayN mysql.Num
DayTotalN mysql.Num
DayStr mysql.Str
Probability mysql.Num
IsUse mysql.YesNo
IsPublicScreen mysql.YesNo
IsScrollScreen mysql.YesNo
IntervalN mysql.Num //间隔次数才能再次获取
ProtectionSecond mysql.Num // 保护的时长
ProtectionSum mysql.Num //保护的金额
ProtectionProbability mysql.Num //变成的概率
}
func LuckyboxAwardInit(model *domain.Model, awardN mysql.ID, awardType luckybox_e.AwardTypeLuckyboxAward, picUrl string, dayN mysql.Num, dayTotalN mysql.Num, probability mysql.Num, isUse mysql.YesNo, isPublicScreen mysql.YesNo, isScrollScreen mysql.YesNo, intervalN mysql.Num) *LuckyboxAward {
return &LuckyboxAward{
Model: model,
AwardN: awardN,
AwardType: awardType,
PicUrl: picUrl,
DayN: dayN,
DayTotalN: dayTotalN,
DayStr: time.Now().Format(utils.COMPACT_DATE_FORMAT),
Probability: probability,
IsUse: isUse,
IsPublicScreen: isPublicScreen,
IsScrollScreen: isScrollScreen,
IntervalN: intervalN,
}
}
func GetLuckyboxAwardNilOrErr(model *domain.Model, id mysql.ID) (*LuckyboxAward, error) {
luckyboxAward := LuckyboxAward{}
if err := model.Db.Model(&LuckyboxAward{}).First(&luckyboxAward, id).Error; err != nil {
return nil, myerr.WrapErr(err)
}
luckyboxAward.Model = model
return &luckyboxAward, nil
}
func (luckyboxAward *LuckyboxAward) Edit(awardN mysql.ID, awardType luckybox_e.AwardTypeLuckyboxAward, picUrl string, dayN mysql.Num, dayTotalN mysql.Num, probability mysql.Num, isUse mysql.YesNo, isPublicScreen mysql.YesNo, isScrollScreen mysql.YesNo, intervalN mysql.Num) *LuckyboxAward {
luckyboxAward.AwardN = awardN
luckyboxAward.AwardType = awardType
luckyboxAward.PicUrl = picUrl
luckyboxAward.DayN = dayN
luckyboxAward.DayTotalN = dayTotalN
luckyboxAward.Probability = probability
luckyboxAward.IsUse = isUse
luckyboxAward.IsPublicScreen = isPublicScreen
luckyboxAward.IsScrollScreen = isScrollScreen
luckyboxAward.IntervalN = intervalN
return luckyboxAward
}
// 幸运盒子用户抽奖记录
type LuckyboxUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
// 0 代表没有中奖
LuckyboxAwardId mysql.ID
//0 代表 没有中奖
AwardN uint64
//0 代表 没有中奖
AwardType luckybox_e.AwardTypeLuckyboxAward
//购买幸运小盒子所需的钻石
BuyDiamond mysql.Num
//奖励价值
AwardDiamond mysql.Num
}
// 获取最大的分数
func GetMaxLuckyboxDiamond(model *domain.Model, userId mysql.ID) (mysql.Num, error) {
luckyboxUser := LuckyboxUser{}
if err := model.Db.Model(&LuckyboxUser{}).Where(&LuckyboxUser{
UserId: userId,
}).Order("award_diamond desc").First(&luckyboxUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, nil
} else {
return 0, myerr.WrapErr(err)
}
}
return luckyboxUser.AwardDiamond, nil
}
func GetSumLuckyboxDiamond(model *domain.Model, userId mysql.ID) (uint64, error) {
type summary struct {
Sum uint64
}
result := summary{}
err := model.Db.Model(&LuckyboxUser{}).
Select("SUM(award_diamond) AS sum").
Where(&LuckyboxUser{
UserId: userId,
}).
First(&result).Error
if err != nil {
return 0, err
}
return result.Sum, err
}
func GetSumLuckyboxDiamondV2(_model *domain.Model, userId mysql.ID) (uint64, error) {
var luckyboxTotalUser LuckyboxTotalUser
if err := _model.Db.Model(LuckyboxTotalUser{}).Where("user_id = ?", userId).
First(&luckyboxTotalUser).Error; err != nil {
if err != gorm.ErrRecordNotFound {
return 0, err
} else {
// gorm.RecordNotFound
luckyboxTotalUser.UserId = userId
}
}
if luckyboxTotalUser.Sync == mysql.YES {
return uint64(luckyboxTotalUser.AwardDiamond), nil
}
// sync before
var awardDiamond, awardN, buyDiamond uint64
type summary struct {
AwardN uint64
BuyDiamond uint64
AwardDiamond uint64
}
result := summary{}
err := _model.Db.Model(&LuckyboxUser{}).
Select("SUM(award_diamond) AS award_diamond,SUM(award_n) as award_n,SUM(buy_diamond) as buy_diamond").
Where(&LuckyboxUser{
UserId: userId,
}).
First(&result).Error
if err != nil {
return 0, err
}
awardDiamond += result.AwardDiamond
awardN += result.AwardN
buyDiamond += result.BuyDiamond
// 备份表
for i := 3; i <= 7; i++ {
table := fmt.Sprintf("luckybox_user_20220%d", i)
result := summary{}
err := _model.Db.Table(table).
Select("SUM(award_diamond) AS award_diamond,SUM(award_n) as award_n,SUM(buy_diamond) as buy_diamond").
Where(&LuckyboxUser{
UserId: userId,
}).
First(&result).Error
if err != nil {
return 0, err
}
awardDiamond += result.AwardDiamond
awardN += result.AwardN
buyDiamond += result.BuyDiamond
}
// 回写总表
luckyboxTotalUser.Sync = mysql.YES
luckyboxTotalUser.BuyDiamond = mysql.Num(buyDiamond)
luckyboxTotalUser.AwardDiamond = mysql.Num(awardDiamond)
luckyboxTotalUser.AwardN = awardN
if err := model.Persistent(mysql.Db, &luckyboxTotalUser); err != nil {
mylogrus.MyLog.Errorf("luckyboxTotalUser fail:%v-%v", luckyboxTotalUser, err)
}
return awardDiamond, err
}
func GetLuckyboxNilOrErr(model *domain.Model) (*Luckybox, error) {
luckybox := Luckybox{}
if err := model.Db.Model(&Luckybox{}).First(&luckybox).Error; err != nil {
return nil, myerr.WrapErr(err)
}
luckybox.Model = model
return &luckybox, nil
}
func GetLucyboxDiamond(model *domain.Model) (uint32, error) {
if luckybox, err := GetLuckyboxNilOrErr(model); err != nil {
return 0, err
} else {
return luckybox.DiamondNum, nil
}
}
// 幸运盒子用户抽奖汇总(周)
type LuckyboxWeekUser struct {
Date string
UserId mysql.ID
BuyDiamond mysql.Num //购买幸运小盒子所需的钻石
AwardDiamond mysql.Num //奖励价值
AwardN uint64
}
func (lwu *LuckyboxWeekUser) AddDiamond(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"buy_diamond": gorm.Expr("buy_diamond + ?", lwu.BuyDiamond),
"award_diamond": gorm.Expr("award_diamond + ?", lwu.AwardDiamond),
"award_n": gorm.Expr("award_n + ?", lwu.AwardN),
}),
}).Create(lwu).Error
}
// 乐透抽奖
func (luckybox *Luckybox) Lottery(userId mysql.ID) (*LuckyboxUser, string, mysql.YesNo, error) {
luckyboxAwards, err := luckybox.getAllValidAward()
if err != nil {
return nil, "", mysql.NO, err
}
//打乱
rand.Shuffle(len(luckyboxAwards), func(i, j int) {
t := luckyboxAwards[i]
luckyboxAwards[i] = luckyboxAwards[j]
luckyboxAwards[j] = t
})
var winLuckyboxAward *LuckyboxAward = nil
var picUrl string = ""
var isPublicScreen mysql.YesNo = mysql.NO
//循环判断
for i, r := range luckyboxAwards {
random := luckybox.getRandomN()
luckybox.Model.Log.Infof("luckybox lottery r.Probability :%v, random :%v, flag:%v userId:%v", r.Probability, random, r.Probability > random, userId)
//间隔了多少, 产品认为只要是大奖,都间隔,同页面显示,数据库存储不太一样
var intervalSum int64 = -1
//产品的逻辑:无论抽多少次,都不能连续抽中大奖。
//产品条件: 不能连续抽中大奖 && 满足概率膨胀 && 每日放出的次数
//实现: 满足概率膨胀 && 不能连续抽中大奖 && 每日放出的次数
//当用户在最近48小时内:
//下注金额-获奖金额≥100,000
//则用户进入抽奖保护期,满足这一条件的中奖概率调整为
//100,000大奖的中奖概率调整为100
if r.ProtectionProbability > 0 {
/* s := luckySum{}
if err := luckybox.Db.Model(&LuckyboxUser{}).Select("SUM(Buy_Diamond - Award_Diamond) AS money").Where(&LuckyboxUser{
UserId: userId,
}).Where("created_time > ?", time.Now().Add(-time.Second * time.Duration(r.ProtectionSecond))).First(&s).Error; err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
}*/
//只是移除一周,因为不知道,不同的奖励周期不一样
redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetLuckyboxBuyAward(userId), "0", strconv.FormatInt(time.Now().AddDate(0, 0, -7).Unix(), 10))
//
var sumMoney int64 = 0
if zList, err := redisCli.GetRedis().ZRevRangeByScore(context.Background(), redis_key.GetLuckyboxBuyAward(userId), &redis2.ZRangeBy{
Min: strconv.FormatInt(time.Now().Add(-time.Second*time.Duration(r.ProtectionSecond)).Unix(), 10),
Max: "+inf",
}).Result(); err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
} else {
for i, _ := range zList {
zs := strings.Split(zList[i], "_")
if len(zs) > 1 {
if money, err := strconv.ParseInt(zs[1], 10, 64); err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
} else {
sumMoney = sumMoney + money
}
}
}
}
luckybox.Model.Log.Infof("luckybox lottery sumMoney:%v > ProtectionSum:%v, userId:%v", sumMoney, r.ProtectionSum, userId)
if sumMoney >= int64(r.ProtectionSum) {
r.Probability = r.ProtectionProbability
luckybox.Model.Log.Infof("luckybox lottery sumMoney:%v > ProtectionSum:%v, userId:%v r.Probability:%v", sumMoney, r.ProtectionSum, userId, r.Probability)
}
}
if r.Probability > random {
//是否符合间隔多少次
if r.IntervalN > 0 {
//
if intervalSum == -1 {
//
luckyboxUserMax := LuckyboxUser{}
if err := luckybox.Db.Model(&LuckyboxUser{}).Where(&LuckyboxUser{
UserId: userId,
}).Where("luckybox_award_id in (select a.id from luckybox_award a where a.is_use = ? and a.interval_n > 0)", mysql.YES).Order("id desc").First(&luckyboxUserMax).Error; err != nil {
/* if err == gorm.ErrRecordNotFound {
intervalSum = 0
} else {
return nil, "", mysql.NO, myerr.WrapErr(err)
}*/
if err != gorm.ErrRecordNotFound {
return nil, "", mysql.NO, myerr.WrapErr(err)
}
}
/* else {
//判断数量
var c int64
if err := luckybox.Db.Model(&LuckyboxUser{}).Where(&LuckyboxUser{
UserId: userId,
}).Where("id > ?", luckyboxUserMax.ID).Count(&c).Error; err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
} else {
intervalSum = c
}
}*/
//luckyboxUserMax 可能为0
//判断数量
var c int64
if err := luckybox.Db.Model(&LuckyboxUser{}).Where(&LuckyboxUser{
UserId: userId,
}).Where("id > ?", luckyboxUserMax.ID).Count(&c).Error; err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
} else {
intervalSum = c
}
}
if int64(r.IntervalN) > intervalSum {
luckybox.Model.Log.Infof("luckybox lottery IntervalN:%v, intervalSum:%v userId:%v", r.IntervalN, intervalSum, userId)
continue
}
}
dayStr := time.Now().Format(utils.COMPACT_DATE_FORMAT)
//预先判断,拦截了部分。查询的时候,已经过滤了,
//if luckyboxAwards[i].DayStr == dayStr && luckyboxAwards[i].DayN >= luckyboxAwards[i].DayTotalN {
// continue
//}
//
txWinLuckyboxAward := luckybox.Db.Model(&luckyboxAwards[i])
if err := txWinLuckyboxAward.Where("is_use = ?", mysql.YES).Where("day_total_n > 0").Where("day_n < ? or day_str <> ? ", luckyboxAwards[i].DayTotalN, dayStr).Updates(map[string]interface{}{"day_n": gorm.Expr("case when day_str = ? then day_n + 1 else 1 end", dayStr), "day_str": gorm.Expr(dayStr)}).Error; err != nil {
//可能形成死锁,单做没抽中
luckybox.Log.Errorf("txWinLuckyboxAward.Where sqlErr:%+v", myerr.WrapErr(err))
continue
//return nil, "", mysql.NO, myerr.WrapErr(err)
}
if txWinLuckyboxAward.RowsAffected == 0 {
print(0)
//没有更新任何数据,则不算中奖
} else {
//已更新了数据,中奖,跳出
winLuckyboxAward = &luckyboxAwards[i]
winLuckyboxAward.Model = luckybox.Model
picUrl = luckyboxAwards[i].PicUrl
isPublicScreen = luckyboxAwards[i].IsPublicScreen
//
luckybox.Model.Log.Infof("luckybox lottery win Probability:%v, random:%v, userId:%v", r.Probability, random, userId)
//
break
}
//严格控制数量,不允许并发超过日临界值值
/* if dayStr == luckyboxAwards[i].DayStr {
//
txWinLuckyboxAward := luckybox.Db.Model(&luckyboxAwards[i])
if err := txWinLuckyboxAward.Where("day_n < ?", luckyboxAwards[i].DayTotalN).UpdateColumn("day_n", gorm.Expr("day_n + 1")).Error; err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
}
if txWinLuckyboxAward.RowsAffected == 0 {
//没有更新任何数据,则不算中奖
} else {
//已更新了数据,中奖,跳出
winLuckyboxAward = &luckyboxAwards[i]
winLuckyboxAward.Model = luckybox.Model
picUrl = luckyboxAwards[i].PicUrl
isPublicScreen = luckyboxAwards[i].IsPublicScreen
break
}
//winLuckyboxAward.DayN = winLuckyboxAward.DayN + 1
} else {
txWinLuckyboxAward := luckybox.Db.Model(&luckyboxAwards[i])
//这里存在并发的问题, 方案1:加上where day_str = dayStr 解决并发,问题在于,对计算概率产生了影响, 方案2:容错并发,day_n=1冲刷了数据。低概率,可接受,产品都接受改数据。
//情况1:先更新 day_n + 1,再更新day_n=1 没有问题。 情况2:先更新day_n=1,再更新day_n+1 没有问题,情况3:先更新day_n=1,再更新day_n=1 fixme:有问题, 解决方案:set case when
if err := txWinLuckyboxAward.Where("day_n < ?", luckyboxAwards[i].DayTotalN).UpdateColumn("day_n", gorm.Expr("1")).UpdateColumn("day_str", gorm.Expr(dayStr)).Error; err != nil {
return nil, "", mysql.NO, myerr.WrapErr(err)
}
if txWinLuckyboxAward.RowsAffected == 0 {
//没有更新任何数据,则不算中奖
} else {
//已更新了数据,中奖,跳出
winLuckyboxAward = &luckyboxAwards[i]
winLuckyboxAward.Model = luckybox.Model
picUrl = luckyboxAwards[i].PicUrl
isPublicScreen = luckyboxAwards[i].IsPublicScreen
break
}
}*/
}
}
luckyboxUser := LuckyboxUser{
Model: luckybox.Model,
UserId: userId,
LuckyboxAwardId: 0,
AwardN: 0,
AwardType: 0,
BuyDiamond: luckybox.DiamondNum,
AwardDiamond: 0,
}
//判断是否中奖
if winLuckyboxAward != nil {
if winLuckyboxAward.AwardType == luckybox_e.Diamond {
luckyboxUser.LuckyboxAwardId = winLuckyboxAward.ID
luckyboxUser.AwardType = winLuckyboxAward.AwardType
luckyboxUser.AwardN = winLuckyboxAward.AwardN
luckyboxUser.AwardDiamond = mysql.Num(winLuckyboxAward.AwardN)
} else {
luckybox.Log.Errorf("Lottery AwardType:%v err", winLuckyboxAward.AwardType)
}
}
return &luckyboxUser, picUrl, isPublicScreen, nil
}
// 获取全部的奖励规则
func (luckybox *Luckybox) getAllValidAward() ([]LuckyboxAward, error) {
dateStr := time.Now().Format(utils.COMPACT_DATE_FORMAT)
luckyboxAwards := []LuckyboxAward{}
if err := luckybox.Db.Model(&LuckyboxAward{}).Where(&LuckyboxAward{
IsUse: mysql.YES,
}).Where("(day_total_n > day_n and day_str = ?) or (day_str <> ?)", dateStr, dateStr).Find(&luckyboxAwards).Error; err != nil {
return nil, myerr.WrapErr(err)
}
return luckyboxAwards, nil
}
// 获取随机数
func (luckybox *Luckybox) getRandomN() uint32 {
return uint32(rand.Intn(100000))
}
// 幸运盒子用户抽奖汇总(总)
type LuckyboxTotalUser struct {
mysql.Entity
UserId mysql.ID
BuyDiamond mysql.Num //购买幸运小盒子所需的钻石
AwardDiamond mysql.Num //奖励价值
AwardN uint64
Sync mysql.YesNo
}
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
import (
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
"time"
)
type UserNoble struct {
mysql.Entity
UserId uint64
Level uint16
EndTime time.Time
}
func (ub *UserNoble) Create(db *gorm.DB) error {
return db.Create(ub).Error
}
func (ub *UserNoble) UpdateEndTime(db *gorm.DB, endTime time.Time) (int64, error) {
r := db.Model(&UserNoble{}).Where(ub).Update("end_time", endTime)
return r.RowsAffected, r.Error
}
// 查询用户未过期的贵族
func (ub *UserNoble) Find(db *gorm.DB) ([]UserNoble, error) {
rows := make([]UserNoble, 0)
if err := db.Where(ub).Where("end_time>=NOW()").Order("level DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
// 查询用户所有的贵族(包括已过期)
func (ub *UserNoble) FindAll(db *gorm.DB) ([]UserNoble, error) {
rows := make([]UserNoble, 0)
if err := db.Where(ub).Order("level DESC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func RemoveNoble(db *gorm.DB, userId uint64, level uint16) error {
ub := UserNoble{
UserId: userId,
Level: level,
}
return ub.Delete(db)
}
func (ub *UserNoble) Delete(db *gorm.DB) 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) {
ub := UserNoble{
UserId: userId,
}
records, err := ub.Find(db)
if err != nil {
return nil, err
}
if len(records) <= 0 {
return nil, nil
}
return &records[0], nil
}
func GetNobleLevel(db *gorm.DB, userId uint64) (uint16, error) {
noble, err := FindActiveNoble(db, userId)
if err != nil {
return 0, err
}
if noble == nil {
return 0, nil
} else {
return noble.Level, nil
}
}
func IsNoble(db *gorm.DB, userId uint64) (bool, error) {
level, err := GetNobleLevel(db, userId)
if err != nil {
return false, err
}
return level > 0, nil
}
func CheckNobleLevel(db *gorm.DB, userId uint64, targetLevel uint16) (bool, error) {
level, err := GetNobleLevel(db, userId)
if err != nil {
return false, err
}
return level >= targetLevel, nil
}
// 分几次获取
// 每次500只
func BatchGetActiveNoble(db *gorm.DB, userIds []uint64) (map[uint64]UserNoble, error) {
ub := UserNoble{}
result := make(map[uint64]UserNoble, 0)
total := len(userIds)
if total <= 0 {
return result, nil
}
var notEndUids []uint64
const NUM = 500
start, end := 0, NUM
for start < total {
if end > total {
end = total
}
tmpUserId := userIds[start:end]
records, err := ub.batchGet(db, tmpUserId)
if err != nil {
return nil, err
}
for _, i := range tmpUserId {
if len(records[i]) > 0 {
result[i] = records[i][0]
notEndUids = append(notEndUids, result[i].UserId)
} else {
result[i] = UserNoble{}
}
}
start += NUM
end += NUM
}
mylogrus.MyLog.Infof("BatchGetActiveNoble expected:%v,actual:%v,notEndUids:%v", len(userIds), len(result), notEndUids)
if len(userIds) != len(result) {
mylogrus.MyLog.Warnf("BatchGetActiveNoble expected:%v", userIds)
}
return result, nil
}
func GetDailyGold(db *gorm.DB, userId uint64) (uint, error) {
level, err := GetNobleLevel(db, userId)
if err != nil {
return 0, err
}
r := ResNoble{}
if err := db.Model(&ResNoble{}).First(&r, level).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, nil
} else {
return 0, myerr.WrapErr(err)
}
}
return r.DailyGold, nil
}
func BatchGetNobleLevel(db *gorm.DB, userIds []uint64) (map[uint64]uint16, error) {
m, err := BatchGetActiveNoble(db, 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
}
\ No newline at end of file
package model
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/myerr"
"time"
)
func Persistent(db *gorm.DB, t mysql.EntityI) error {
if t == nil {
return nil
}
if t.IsLazyLoad() {
return nil
}
//删除
if t.CheckDel() {
tx := db.Delete(t)
if err := tx.Error; err != nil {
return myerr.WrapErr(err)
}
if tx.RowsAffected == 0 {
return myerr.NewWaring("gorm delete.RowsAffected = 0")
}
//增加缓存行为记录(删除)
} else if t.GetID() == 0 {
//新增
if t.CheckOnDuplicateKeyUPDATE() {
if err := db.Set("gorm:insert_option", fmt.Sprintf("ON DUPLICATE KEY UPDATE `created_time` = '%s'", time.Now())).Create(t).Error; err != nil {
return myerr.WrapErr(err)
}
} else if t.CheckOnDuplicateKeyIGNORE() {
if err := db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(t).Error; err != nil {
return myerr.WrapErr(err)
}
} else {
if err := db.Create(t).Error; err != nil {
return myerr.WrapErr(err)
}
}
//增加缓存行为记录(新增)
} else {
//fixme: 更新条件,目前是互斥的,应该改成且。
//更新
if t.CheckUpdateVersion() {
//版本号。乐观锁更新,注意,空值不更新
tx := db.Model(t).Where("version = ? ", t.GetUpdateVersionBefore()).Updates(t)
if err := tx.Error; err != nil {
return myerr.WrapErr(err)
}
if tx.RowsAffected == 0 {
return myerr.NewWaring("gorm version update.RowsAffected = 0")
}
} else if t.CheckUpdateCondition() {
//条件更新
tx := db.Model(t).Where(t.GetUpdateCondition()).Updates(t)
if err := tx.Error; err != nil {
return myerr.WrapErr(err)
}
if tx.RowsAffected == 0 {
return myerr.NewWaring("gorm condition update.RowsAffected = 0")
}
} else if len(t.GetOmit()) > 0 {
if err := db.Model(t).Omit(t.GetOmit()...).Save(t).Error; err != nil {
return myerr.WrapErr(err)
}
} else {
if err := db.Model(t).Save(t).Error; err != nil {
return myerr.WrapErr(err)
}
}
//增加缓存行为记录(更新)
}
return nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/myerr"
)
type ResCode struct {
mysql.Entity
*domain.Model `gorm:"-"`
Code string
}
/**
* true: 不存在成功, false: 已存在,不成功
*/
func CheckCode(model *domain.Model, code string) (bool, error) {
var n int64
if err := model.Db.Model(&ResCode{
Code: code,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
if n == 0 {
return true, nil
} else {
return false, nil
}
}
...@@ -196,3 +196,4 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) { ...@@ -196,3 +196,4 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) {
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"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/gift_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
)
type ResGift struct {
mysql.Entity
//*domain.ModelBase `gorm:"-"`
*domain.Model `gorm:"-"`
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
}
func (rg *ResGift) FindValid(db *gorm.DB) ([]ResGift, error) {
rows := make([]ResGift, 0)
rg.Status = mysql.USER
if err := db.Where(rg).Order("n ASC").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
type ResGiftAvatar struct {
mysql.Entity
//*domain.ModelBase `gorm:"-"`
*domain.Model `gorm:"-"`
ResGiftId mysql.ID
Type gift_e.ResGiftAvatarType
SendUserId mysql.ID
ReceiverUserId mysql.ID
}
func (rga *ResGiftAvatar) Find(db *gorm.DB) ([]ResGiftAvatar, error) {
rows := make([]ResGiftAvatar, 0)
if err := db.Where(rga).Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (rga *ResGiftAvatar) Save(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"send_user_id"}),
}).Create(rga).Error
}
func GetResGiftAvatar(model *domain.Model, t gift_e.ResGiftAvatarType) (ResGiftAvatar, error) {
resGiftAvatar := ResGiftAvatar{}
if err := model.Db.Model(&ResGiftAvatar{}).Where(&ResGiftAvatar{
Type: t,
}).First(&resGiftAvatar).Error; err != nil {
return ResGiftAvatar{}, myerr.WrapErr(err)
}
return resGiftAvatar, nil
}
/**
* 获取礼物
**/
func GetGiftWithValid(model *domain.Model, id mysql.ID) (*ResGift, error) {
var resGift ResGift
if err := model.Db.First(&resGift, id).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if resGift.Status == mysql.NOUSER {
return nil, bizerr.ResGiftNoUser
}
return &resGift, nil
}
func (gift *ResGift) StatusToCancle() *ResGift {
gift.Status = 1
return gift
}
/**
* 根据排序号查询礼物配置
**/
func GetGiftByOrderId(model *domain.Model, n mysql.Num) (*ResGift, error) {
var resGift ResGift
if err := model.Db.Where("n = ?", n).First(&resGift).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return &resGift, nil
}
/**
* 添加礼物配置
**/
func AddGiftConfig(model *domain.Model, input ResGift) error {
return model.Db.Create(&input).Error
}
/**
* 修改礼物配置
**/
func UpdateGift(model *domain.Model, input ResGift) error {
return model.Db.Omit("music_url", "GroupBroadcast", "cp", "together").Save(&input).Error
}
func UpdateGiftStatus(model *domain.Model, giftId mysql.ID, status mysql.UserYesNo) error {
return model.Db.Table("res_gift").Where("id = ?", giftId).Update("status", status).Error
}
func GetGiftN(db *gorm.DB, n mysql.Num) ([]mysql.Num, error) {
rows := make([]ResGift, 0)
if err := db.Model(&ResGift{}).Where("n >= ?", n).Order("n").Find(&rows).Error; err != nil {
return nil, err
}
result := make([]mysql.Num, 0)
for _, i := range rows {
result = append(result, i.N)
}
return result, nil
}
func UpdateGiftN(model *domain.Model, beginN, endN mysql.Num) error {
return model.Db.Table("res_gift").Where("n >= ? AND n < ?", beginN, endN).Update("n", gorm.Expr("n+1")).Error
}
type GiftDetailInfo struct {
IconUrl string `json:"iconUrl"`
SvgaUrl string `json:"svgaUrl"`
SenderAvatar string `json:"senderAvatar"` //key:sender_avatar
ReceiverAvatar string `json:"receiverAvatar"` //key:receiver_avatar
}
\ No newline at end of file
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/res_e"
"hilo-group/myerr"
)
type ResGroupSupport struct {
mysql.Entity
*domain.Model `gorm:"-"`
Grade res_e.ResGroupSupportGrade
ContributeUserNum mysql.Num
ContributeDiamondNum mysql.Num
MgrNum mysql.Num
AdminAward mysql.Num
MgrAward mysql.Num
Status mysql.UserYesNo
}
func GetResGroupSupportById(model *domain.Model, id mysql.ID) (ResGroupSupport, error) {
resGroupSupport := ResGroupSupport{}
if err := model.Db.Model(&ResGroupSupport{}).Where(&ResGroupSupport{Status: mysql.USER}).First(&resGroupSupport, id).Error; err != nil {
return ResGroupSupport{}, myerr.WrapErr(err)
}
return resGroupSupport, nil
}
func GetResGroupSupportByValid(model *domain.Model) ([]ResGroupSupport, error) {
resGroupSupports := []ResGroupSupport{}
if err := model.Db.Model(&ResGroupSupport{}).Where(&ResGroupSupport{
Status: mysql.USER,
}).Order("grade asc").Find(&resGroupSupports).Error; err != nil {
return nil, myerr.WrapErr(err)
}
return resGroupSupports, nil
}
func GetResGroupSupportBy(model *domain.Model, contributeUserNum uint32, contributeDiamondNum uint64) (*ResGroupSupport, error) {
resGroupSupport := ResGroupSupport{}
if err := model.Db.Model(&ResGroupSupport{}).Where(&ResGroupSupport{
Status: mysql.USER,
}).Where("contribute_user_num <= ? AND contribute_diamond_num <= ?", contributeUserNum, contributeDiamondNum).Order("grade DESC").First(&resGroupSupport).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return &resGroupSupport, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
)
type ResGroupTheme struct {
mysql.Entity
Name string
Url string
Weight int
Status uint8
}
// 查询所有的主题
func GroupThemeGetAll(db *gorm.DB) ([]ResGroupTheme, error) {
rows := make([]ResGroupTheme, 0)
err := db.Model(&ResGroupTheme{}).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
// 查询上架中的主题
func GroupThemeGetAllInUse(db *gorm.DB) ([]ResGroupTheme, error) {
rows := make([]ResGroupTheme, 0)
err := db.Where(&ResGroupTheme{Status: group_e.SWITCH_ON}).Order("weight DESC, id").Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func (gt *ResGroupTheme) Get(db *gorm.DB) error {
return db.Model(&ResGroupTheme{}).Where(gt).First(gt).Error
}
func (gt *ResGroupTheme) Create(db *gorm.DB) error {
return db.Model(&gt).Create(gt).Error
}
func (gt *ResGroupTheme) Save(db *gorm.DB) error {
return db.Save(gt).Error
}
func (gt *ResGroupTheme) SaveWeight(db *gorm.DB) error {
return db.Model(gt).Update("weight", gt.Weight).Error
}
func (gt *ResGroupTheme) SaveStatus(db *gorm.DB) error {
return db.Model(gt).Update("status", gt.Status).Error
}
func (gt *ResGroupTheme) SelectWeightAbove(db *gorm.DB) ([]ResGroupTheme, error) {
rows := make([]ResGroupTheme, 0)
if err := db.Model(&ResGroupTheme{}).Where("weight >= ?", gt.Weight).Order("weight").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (gt *ResGroupTheme) IncreaseWeight(db *gorm.DB, ids []uint64) error {
return db.Model(&ResGroupTheme{}).Where("id in ?", ids).Update("weight", gorm.Expr("weight + 1")).Error
}
func (gt *ResGroupTheme) Switch(db *gorm.DB, status uint8) error {
return db.Where(gt).Update("status = ?", status).Error
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
)
type ResHeadwear struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
}
func GetResHeadwearById(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)
}
resHeadwear.Model = model
return &resHeadwear, 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
}
//矛盾,项目负责人(产品不接受 商品 同上架分开两个数据结构的模式),又在页面上要求头饰同价格在一起展示,修改。
//目前违背了,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 GetResHeadwearDiamond(model *domain.Model, resHeadwearDiamondId mysql.ID) (*ResHeadwearDiamond, error) {
resHeadwearDiamond := ResHeadwearDiamond{}
if err := model.Db.Model(&ResHeadwearDiamond{}).First(&resHeadwearDiamond, resHeadwearDiamondId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if resHeadwearDiamond.Status == mysql.NOUSER {
return nil, bizerr.ResHeadwearDiamondNoUse
}
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
}
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
}
}
//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 BatchGetHeadwearByIds(model *domain.Model, ids []mysql.ID) (map[uint64]ResHeadwear, error) {
resHeadwears := []ResHeadwear{}
if err := model.Db.Model(&ResHeadwear{}).Where("id in (?)", ids).Find(&resHeadwears).Error; err != nil {
return nil, myerr.WrapErr(err)
}
resHeadwearMap := map[uint64]ResHeadwear{}
for i, r := range resHeadwears {
resHeadwearMap[r.ID] = resHeadwears[i]
}
return resHeadwearMap, 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
}
package res_m package res_m
import ( import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"github.com/bluele/gcache"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-group/_const/enum/res_e" "hilo-group/_const/enum/res_e"
"hilo-group/myerr"
"time"
) )
type ResMedal struct { type ResMedal struct {
...@@ -41,3 +45,85 @@ func GetUserMedalLevelMap(db *gorm.DB) (map[uint64]uint8, map[uint8][]uint64, er ...@@ -41,3 +45,85 @@ func GetUserMedalLevelMap(db *gorm.DB) (map[uint64]uint8, map[uint8][]uint64, er
} }
return medalTypes, result, nil return medalTypes, result, nil
} }
type RoomMedalConfig struct {
Level uint16
Threshold uint64
Desc string
InactiveUrl string
ActiveUrl string
}
func GetRoomMedalConfig(db *gorm.DB) ([]RoomMedalConfig, error) {
rows := make([]RoomMedalConfig, 0)
if err := db.Model(&RoomMedalConfig{}).Order("level").Find(&rows).Error; err != nil {
return nil, err
}
return rows, 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
}
//每个公开勋章都要有对应的获得来源,
type ResMedalPublicObtain struct {
mysql.Entity
Type res_e.ResMedalObtainType
ResMedalId mysql.ID
ResGiftId mysql.ID
}
func ResMedalObtainGetByMedalId(model *domain.Model, medalId mysql.ID) (*ResMedalPublicObtain, error) {
resMedalPublicObtain := ResMedalPublicObtain{}
if err := model.Db.Model(&ResMedalPublicObtain{}).Where(&ResMedalPublicObtain{
ResMedalId: medalId,
}).First(&resMedalPublicObtain).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return &resMedalPublicObtain, nil
}
func GetResMedalById(model *domain.Model, id mysql.ID) (ResMedal, error) {
resMedal := ResMedal{}
if err := model.Db.Model(&ResMedal{}).First(&resMedal, id).Error; err != nil {
return resMedal, myerr.WrapErr(err)
}
return resMedal, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/res_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
)
type ResProperty struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
}
type ResPropertyDiamond struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResPropertyId mysql.ID
DiamondNum mysql.Num
Second mysql.Num
Status mysql.UserYesNo
}
type ResPropertyAvatar struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResPropertyId mysql.ID
Type res_e.ResPropertyAvatarType
SendUserId mysql.ID
ReceiverUserId mysql.ID
}
func InitResPropertyDiamond(model *domain.Model, resPropertyId mysql.ID, diamondNum mysql.Num, second mysql.Num) *ResPropertyDiamond {
return &ResPropertyDiamond{
Model: model,
ResPropertyId: resPropertyId,
DiamondNum: diamondNum,
Second: second,
Status: mysql.NOUSER,
}
}
//id获取头饰,不存在则抛异常
func GetPropertyById(model *domain.Model, id mysql.ID) (*ResProperty, error) {
resProperty := ResProperty{}
if err := model.Db.Model(&ResProperty{}).First(&resProperty, id).Error; err != nil {
return nil, myerr.WrapErr(err)
} else {
resProperty.Model = model
return &resProperty, nil
}
}
func GetResPropertyDiamond(model *domain.Model, resPropertyDiamondId mysql.ID) (*ResPropertyDiamond, error) {
resPropertyDiamond := ResPropertyDiamond{}
if err := model.Db.Model(&ResPropertyDiamond{}).First(&resPropertyDiamond, resPropertyDiamondId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if resPropertyDiamond.Status == mysql.NOUSER {
return nil, bizerr.ResPropertyDiamondNoUse
}
return &resPropertyDiamond, nil
}
func GetResPropertyDiamondByPropertyIdOrNil(model *domain.Model, resPropertyId mysql.ID) (*ResPropertyDiamond, error) {
resPropertyDiamond := ResPropertyDiamond{}
if err := model.Db.Model(&ResPropertyDiamond{}).Where(&ResPropertyDiamond{
ResPropertyId: resPropertyId,
}).First(&resPropertyDiamond).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resPropertyDiamond.Model = model
return &resPropertyDiamond, nil
}
//设置成未使用
func (resPropertyDiamond *ResPropertyDiamond) SetUser() *ResPropertyDiamond {
resPropertyDiamond.Status = mysql.USER
return resPropertyDiamond
}
//设置成未使用
func (resPropertyDiamond *ResPropertyDiamond) SetNoUser() *ResPropertyDiamond {
resPropertyDiamond.Status = mysql.NOUSER
return resPropertyDiamond
}
func (resPropertyDiamond *ResPropertyDiamond) SetDiamondNum(diamondNum uint32) *ResPropertyDiamond {
resPropertyDiamond.DiamondNum = diamondNum
return resPropertyDiamond
}
func (resPropertyDiamond *ResPropertyDiamond) SetSecond(second uint32) *ResPropertyDiamond {
resPropertyDiamond.Second = second
return resPropertyDiamond
}
func AddProperty(model *domain.Model, p *ResProperty) error {
return model.Db.Create(p).Error
}
func EditProperty(model *domain.Model, propertyId uint64, name, picUrl, effectUrl string) error {
activityConfig := ResProperty{Entity: mysql.Entity{ID: propertyId}}
err := model.Db.First(&activityConfig).Error
if err != nil {
return err
}
activityConfig.Name = name
activityConfig.PicUrl = picUrl
activityConfig.EffectUrl = effectUrl
return model.Db.Save(&activityConfig).Error
}
func (p *ResProperty) Get(db *gorm.DB) error {
return db.Where(p).First(p).Error
}
func (p *ResProperty) GetAll(db *gorm.DB) (map[uint64]ResProperty, error) {
rows := make([]ResProperty, 0)
if err := db.Where(p).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]ResProperty, 0)
for _, i := range rows {
result[i.ID] = i
}
return result, nil
}
func (p *ResPropertyAvatar) GetAll(db *gorm.DB) (map[uint64]ResPropertyAvatar, error) {
rows := make([]ResPropertyAvatar, 0)
if err := db.Where(p).Find(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
result := make(map[uint64]ResPropertyAvatar, 0)
for _, i := range rows {
result[i.ResPropertyId] = i
}
return result, nil
}
package rocket_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
)
type RocketAwardConfig struct {
mysql.Entity
Stage uint16
Seq uint16
AwardType uint16
AwardId uint64
Num uint32
Duration uint32
Probability uint16
}
// fixme:处理重复ID
func (rac *RocketAwardConfig) GetAll(db *gorm.DB) (map[uint16][]RocketAwardConfig, error) {
rows := make([]RocketAwardConfig, 0)
if err := db.Where(rac).Order("Seq").Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint16][]RocketAwardConfig, 0)
for _, i := range rows {
if _, ok := result[i.Stage]; !ok {
result[i.Stage] = make([]RocketAwardConfig, 0)
}
result[i.Stage] = append(result[i.Stage], i)
}
return result, nil
}
// fixme:处理重复ID
func GetAwardConfigByStage(db *gorm.DB, stage uint16) ([]RocketAwardConfig, error) {
rows := make([]RocketAwardConfig, 0)
if err := db.Model(&RocketAwardConfig{}).Where("stage = ?", stage).Order("Seq").Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
type RocketAward struct {
mysql.Entity
ResultId uint64
UserId uint64
Rank uint16
AwardCfgId uint64
Diamond uint32
}
func (ra *RocketAward) Create(db *gorm.DB) error {
return db.Create(ra).Error
}
func (ra *RocketAward) BatchGetRank(db *gorm.DB, ids []uint64) (map[uint64]uint64, error) {
result := make(map[uint64]uint64, 0)
// ids为空就不用查了
if len(ids) <= 0 {
return result, nil
}
rows := make([]RocketAward, 0)
if err := db.Where(ra).Where("result_id IN ?", ids).Find(&rows).Error; err != nil {
return nil, err
}
for _, i := range rows {
result[i.ResultId] = i.UserId
}
return result, nil
}
func (ra *RocketAward) BatchGetAward(db *gorm.DB, ids []uint64) (map[uint64]RocketAward, error) {
result := make(map[uint64]RocketAward, 0)
if len(ids) <= 0 { // 优化ids空的时候就别查库了
return result, nil
}
rows := make([]RocketAward, 0)
if err := db.Where(ra).Where("result_id IN ?", ids).Find(&rows).Error; err != nil {
return nil, err
}
for _, i := range rows {
result[i.ResultId] = i
}
return result, nil
}
func (ra *RocketAward) GetTopRank(db *gorm.DB, rank uint16) (map[uint64]uint16, error) {
rows := make([]RocketAward, 0)
if err := db.Where(ra).Where("`rank` > 0 AND `rank` <= ?", rank).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64]uint16, 0)
for _, i := range rows {
result[i.UserId] = i.Rank
}
return result, nil
}
func (ra *RocketAward) GetDiamondTotal(db *gorm.DB) (uint32, error) {
type rec struct {
D uint32
}
row := rec{}
if err := db.Model(&RocketAward{}).Select("SUM(diamond) AS d").Where(ra).Where("`rank` = ?", ra.Rank).First(&row).Error; err != nil {
return 0, err
}
return row.D, nil
}
// 查询用户获取3级火箭第一名的次数
func GetUserTopCount(db *gorm.DB, userId uint64) (int64, error) {
var count int64 = 0
if err := db.Table("rocket_result rr ").Joins("INNER JOIN rocket_award ra on rr.id = ra.result_id").
Where("stage = ? AND `rank` = ? AND user_id = ?", 2, 1, userId).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
type RocketGuestAward struct {
Stage uint16
LowerBound uint32
UpperBound uint32
Total uint32
Probability uint16
}
func GetGuestAwardConfig(db *gorm.DB, stage uint16) ([]RocketGuestAward, error) {
rows := make([]RocketGuestAward, 0)
if err := db.Model(&RocketGuestAward{}).Where("stage = ?", stage).Find(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
type RocketAwardEvent struct {
//Stage uint16
//Seq uint16
RocketAwardId uint64
UserId uint64
AwardType uint16
AwardId uint64
Num uint32
Duration uint32
//Probability uint16
}
package rocket_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"time"
)
type RocketContribute struct {
mysql.Entity
GroupId string
Period string
Round uint16
Stage uint16
UserId uint64
GiftRefId uint64
Diamond uint32
}
func (rc *RocketContribute) Create(db *gorm.DB) error {
return db.Create(rc).Error
}
func (rc *RocketContribute) Get(db *gorm.DB) ([]RocketContribute, error) {
rows := make([]RocketContribute, 0)
err := db.Where(rc).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, err
}
type ContributeType struct {
UserId uint64
Diamond uint32
}
func (rc *RocketContribute) SumByStageUser(db *gorm.DB, round uint16) (map[uint16][]ContributeType, error) {
type rowType struct {
Stage uint16
UserId uint64
S uint32
}
rows := make([]rowType, 0)
err := db.Model(rc).Select("stage, user_id,SUM(diamond) AS s").
Where(rc).Where("round = ?", round).
Group("stage, user_id").Order("s DESC, created_time ASC").Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[uint16][]ContributeType, 0)
for _, i := range rows {
if _, ok := result[i.Stage]; !ok {
result[i.Stage] = make([]ContributeType, 0)
}
result[i.Stage] = append(result[i.Stage], ContributeType{
UserId: i.UserId,
Diamond: i.S,
})
}
return result, err
}
func (rc *RocketContribute) SumByUser(db *gorm.DB, round, stage uint16) ([]ContributeType, error) {
type rowType struct {
UserId uint64
S uint32
}
rows := make([]rowType, 0)
err := db.Model(rc).Select("user_id,SUM(diamond) AS s").
Where(rc).Where("round = ? AND stage = ?", round, stage).
Group("user_id").Order("s DESC, created_time ASC").Find(&rows).Error
if err != nil {
return nil, err
}
result := make([]ContributeType, 0)
for _, i := range rows {
result = append(result, ContributeType{
UserId: i.UserId,
Diamond: i.S,
})
}
return result, err
}
type RocketResult struct {
mysql.Entity
GroupId string
Period string
Round uint16
Stage uint16
IsAwarded bool
}
func (rr *RocketResult) Create(db *gorm.DB) error {
return db.Create(rr).Error
}
func (rr *RocketResult) Get(db *gorm.DB) ([]RocketResult, error) {
rows := make([]RocketResult, 0)
err := db.Model(&RocketResult{}).Where(rr).Find(&rows).Error
if err != nil {
return nil, nil
}
return rows, nil
}
func (rr *RocketResult) GetByRound(db *gorm.DB, round uint16) (map[uint16]RocketResult, error) {
rows := make([]RocketResult, 0)
err := db.Model(&RocketResult{}).Where(rr).Where("round = ?", round).Find(&rows).Error
if err != nil {
return nil, nil
}
result := make(map[uint16]RocketResult, 0)
for _, i := range rows {
result[i.Stage] = i
}
return result, nil
}
func (rr *RocketResult) GetByTopRound(db *gorm.DB) (map[uint16]RocketResult, error) {
rows := make([]RocketResult, 0)
err := db.Model(&RocketResult{}).Where(rr).Find(&rows).Error
if err != nil {
return nil, nil
}
topRound := -1
for _, i := range rows {
if int(i.Round) > topRound {
topRound = int(i.Round)
}
}
result := make(map[uint16]RocketResult, 0)
for _, i := range rows {
if int(i.Round) == topRound {
result[i.Stage] = i
}
}
return result, nil
}
func (rr *RocketResult) GetValid(db *gorm.DB, t time.Time) ([]RocketResult, error) {
rows := make([]RocketResult, 0)
err := db.Model(&RocketResult{}).Where(rr).Where("created_time > ?", t).Find(&rows).Error
if err != nil {
return nil, nil
}
return rows, nil
}
func (rr *RocketResult) UpdateIsAwarded(db *gorm.DB) (int64, error) {
result := db.Model(&RocketResult{}).Where(rr).Update("is_awarded", true)
if result.Error != nil {
return 0, nil
}
return result.RowsAffected, nil
}
// 取本自然周内最高级的一次火箭
func (rr *RocketResult) GetMaxStage(db *gorm.DB, groupIds []string) (map[string]uint16, error) {
type maxStage struct {
GroupId string
M uint16
}
period := utils.GetMonday(time.Now()).Format(utils.DATE_FORMAT)
rows := make([]maxStage, 0)
err := db.Model(&RocketResult{}).Select("group_id, MAX(stage) AS m").Where(rr).
Where("group_id IN ? AND period >= ?", groupIds, period).Group("group_id").Find(&rows).Error
if err != nil {
return nil, nil
}
result := make(map[string]uint16, 0)
for _, i := range rows {
result[i.GroupId] = i.M
}
return result, nil
}
package rocket_m
import (
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"runtime/debug"
"time"
)
type RocketInfo struct {
mysql.Entity
GroupId string
Period string
Round uint16
Stage uint16
Score uint32
}
func (ri *RocketInfo) Get(db *gorm.DB) error {
err := db.Where(ri).First(ri).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
ri.ID = 0
return nil
} else {
return err
}
}
return nil
}
func (ri *RocketInfo) AddScore(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "group_id"}, {Name: "period"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"score": gorm.Expr("score + ?", ri.Score)}),
}).Create(ri).Error
}
func (ri *RocketInfo) Save(db *gorm.DB) error {
return db.Save(ri).Error
}
// 周期是东3区的23点,即东8区的4点
func GetPeriod(t time.Time) string {
local := t.Local()
return local.Add(-time.Hour * 4).Format(utils.DATE_FORMAT)
}
type RocketStage struct {
Id uint16
Diamond uint32 // 升级需要的钻石数
}
func (rs *RocketStage) GetAll(db *gorm.DB) (map[uint16]uint32, error) {
rows := make([]RocketStage, 0)
if err := db.Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint16]uint32, 0)
for _, i := range rows {
result[i.Id] = i.Diamond
}
return result, nil
}
//执行事务,遇到错误或异常则回滚 todo:应该移动到package mysql下
func DoTransaction(action func(db *gorm.DB) error) error {
begin := time.Now()
db := mysql.Db.Begin()
//异常回调
defer func() {
if err := recover(); err != nil {
//service.MyContext.Log.Info(string(debug.Stack()))
mylogrus.MyLog.Errorf("doTransactional SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
db.Rollback()
//为了防止给controller层造成数据错误,继续抛恐慌
panic(err)
}
}()
err := action(db)
if err != nil {
db.Rollback()
return err
}
//提交
db.Commit()
end := time.Now()
mylogrus.MyLog.Infof("transcation takes %s", end.Sub(begin).String())
return nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_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-group/_const/enum/headwear_e"
"hilo-group/domain/model/res_m"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"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 GetUserHeadwearOrErr(model *domain.Model, userId mysql.ID, headwearId mysql.ID) (*UserHeadwear, error) {
userHeadwear := UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
HeadwearId: headwearId,
}).First(&userHeadwear).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userHeadwear.Model = model
return &userHeadwear, 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
}
func BatchGetUserHeadwearUsing(model *domain.Model, userIds []mysql.ID) (map[uint64]UserHeadwear, error) {
userHeadwears := []UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where("end_time > ?", time.Now()).Where("user_id in (?)", userIds).Order("`using` ASC, updated_time ASC").Find(&userHeadwears).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userHeadwearMap := map[uint64]UserHeadwear{}
for i, r := range userHeadwears {
userHeadwears[i].Model = model
userHeadwearMap[r.UserId] = userHeadwears[i]
}
return userHeadwearMap, nil
}
func (userHeadwear *UserHeadwear) Give(receiveUserId mysql.ID) (*UserHeadwear, *UserHeadwear, uint32, error) {
remainSecond := userHeadwear.EndTime.Unix() - time.Now().Unix()
if remainSecond <= 0 {
return nil, nil, 0, bizerr.UserHeadwearHasEnd
}
receiveUserHeadwear, err := GetUserHeadwearOrInit(userHeadwear.Model, receiveUserId, userHeadwear.HeadwearId)
if err != nil {
return nil, nil, 0, err
}
receiveUserHeadwear, _, err = receiveUserHeadwear.AddEndTime(headwear_e.Give, uint32(remainSecond), userHeadwear.UserId)
if err != nil {
return nil, nil, 0, err
}
_, err = addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, headwear_e.Give, headwear_e.Del, nil, nil, userHeadwear.UserId)
if err != nil {
return nil, nil, 0, err
}
userHeadwear.SetDel()
return userHeadwear, receiveUserHeadwear, uint32(remainSecond), 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) UpdateEndTime(t headwear_e.UserHeadwearLogOrginType, time time.Time, operateUserId mysql.ID) (*UserHeadwear, mysql.ID, error) {
logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, t, headwear_e.UpdateEndTime, nil, &time, operateUserId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
//if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil {
// return nil, logId, nil
//}
userHeadwear.EndTime = time
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
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/user_e"
"hilo-group/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/config"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
"time"
)
type MatchSetActityDailyType mysql.Type
const (
//视频通话
video MatchSetActityDailyType = 1
//点击喜欢
clickLike MatchSetActityDailyType = 2
//点击消息
clickMsg MatchSetActityDailyType = 3
//匹配通过达到某个时间值
matchConfirmTimeDailyType = 4
//群组消息
groupMsgDailyType = 5
//上麦
inMic = 6
)
/**
* 每日的活跃分数设置
**/
type MatchActitySetDaily struct {
mysql.Entity
*domain.Model `gorm:"-"`
Type MatchSetActityDailyType
Score mysql.Num
MaxScore mysql.Num
}
/**
* 用户活跃分数
**/
type MatchActityUserScore struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Score mysql.Num
Grade mysql.Num
matchActityUserScoreDaily *MatchActityUserScoreDaily `gorm:"-"`
}
/**
* 用户活跃分数,每日
**/
type MatchActityUserScoreDaily struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Score mysql.Num
Type MatchSetActityDailyType
Daily mysql.Str
}
/**
* 获取的分数同等级关系
**/
type MatchActitySetScoreGrade struct {
mysql.Entity
*domain.Model `gorm:"-"`
MinNum mysql.Num
MaxNum mysql.Num
Grade mysql.Num
}
//获取活跃等级
func GetActityGrade(model *domain.Model, userId mysql.ID) (uint32, uint32, error) {
var actityUserScore MatchActityUserScore
if err := model.Db.Model(&MatchActityUserScore{}).Where(&MatchActityUserScore{UserId: userId}).First(&actityUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, 0, nil
} else {
return 0, 0, myerr.WrapErr(err)
}
}
return actityUserScore.Grade, actityUserScore.Score, nil
}
func getMatchActityUserScore(model *domain.Model, userId mysql.ID) (*MatchActityUserScore, error) {
var matchActityUserScore MatchActityUserScore
if err := model.Db.Where(&MatchActityUserScore{
UserId: userId,
}).First(&matchActityUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
matchActityUserScore = MatchActityUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, err
}
}
matchActityUserScore.Model = model
return &matchActityUserScore, nil
}
/**
* 检查每日的某个类别的分数,
* return false: 分数未满,true:分数已满了.
**/
func (matchActityUserScore *MatchActityUserScore) checkDailyTypeScore(t MatchSetActityDailyType, daily mysql.Str) (bool, *MatchActityUserScoreDaily, mysql.Num, error) {
var matchActitySetDaily MatchActitySetDaily
if err := matchActityUserScore.Db.Where(&MatchActitySetDaily{
Type: t,
}).First(&matchActitySetDaily).Error; err != nil {
return false, nil, 0, myerr.WrapErr(err)
}
//
var matchActityUserScoreDaily MatchActityUserScoreDaily
if err := matchActityUserScore.Db.Where(&MatchActityUserScoreDaily{
UserId: matchActityUserScore.UserId,
Type: t,
Daily: daily,
}).First(&matchActityUserScoreDaily).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return false, &MatchActityUserScoreDaily{
UserId: matchActityUserScore.UserId,
Score: 0,
Type: t,
Daily: daily,
}, matchActitySetDaily.Score, nil
} else {
return false, nil, matchActitySetDaily.Score, nil
}
}
//
if matchActitySetDaily.MaxScore >= matchActityUserScoreDaily.Score {
if matchActitySetDaily.MaxScore > (matchActityUserScoreDaily.Score + matchActitySetDaily.Score) {
return false, &matchActityUserScoreDaily, matchActitySetDaily.Score, nil
} else {
return false, &matchActityUserScoreDaily, matchActitySetDaily.MaxScore - matchActityUserScoreDaily.Score, nil
}
} else {
return true, &matchActityUserScoreDaily, matchActitySetDaily.Score, nil
}
}
//获取当前的时间字符串
func getDailyStr() string {
return time.Now().Format("2006-01-02")
}
/**
* 增加分数
**/
func (matchActityUserScore *MatchActityUserScore) addScore(t MatchSetActityDailyType) error {
dailyStr := mysql.Str(getDailyStr())
flag, matchActityUserScoreDaily, addScore, err := matchActityUserScore.checkDailyTypeScore(t, dailyStr)
if err != nil {
return err
}
//增加分数
if flag == false {
//检查vip
//检查VIP,是否要*1.5倍
user, err := GetUser(matchActityUserScore.Model, matchActityUserScore.UserId)
if err != nil {
return err
}
isVip, err := user.CheckVip()
if err != nil {
return err
}
//
if isVip {
addScore = addScore * mysql.Num(config.GetGradeConfig().ACTITY_SPEED_VIP) / 10
}
//接受高并发容错
matchActityUserScoreDaily.Score = matchActityUserScoreDaily.Score + addScore
//对应分数
matchActityUserScore.Score = matchActityUserScore.Score + addScore
//对应其等级
var matchActitySetScoreGrade MatchActitySetScoreGrade
if err := matchActityUserScore.Db.Where("min_num <= ? AND max_num >= ?", matchActityUserScore.Score, matchActityUserScore.Score).First(&matchActitySetScoreGrade).Error; err != nil {
return myerr.WrapErr(err)
}
matchActityUserScore.Grade = matchActitySetScoreGrade.Grade
matchActityUserScore.matchActityUserScoreDaily = matchActityUserScoreDaily
return nil
} else {
matchActityUserScore.IsLazyLoad()
return nil
}
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/match_e"
"hilo-group/myerr"
)
/**
* 用户魅力分数
**/
type MatchCharmUserScore struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Score mysql.Num
Grade mysql.Num
}
//获取魅力等级
func GetCharmGrade(model *domain.Model, userId mysql.ID) (uint32, uint32, error) {
var charmUserScore MatchCharmUserScore
if err := model.Db.Model(&MatchCharmUserScore{}).Where(&MatchCharmUserScore{
UserId: userId,
}).First(&charmUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return 0, 0, nil
} else {
return 0, 0, myerr.WrapErr(err)
}
}
return charmUserScore.Grade, charmUserScore.Score, 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
}
func getMatchCharmUserScore(model *domain.Model, userId mysql.ID) (*MatchCharmUserScore, error) {
var matchCharmUserScore MatchCharmUserScore
if err := model.Db.Where(&MatchCharmUserScore{
UserId: userId,
}).First(&matchCharmUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
matchCharmUserScore = MatchCharmUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, err
}
}
matchCharmUserScore.Model = model
return &matchCharmUserScore, nil
}
/**
* 增加分数
**/
func (matchCharmUserScore *MatchCharmUserScore) updateScore(diamondNum mysql.Num) error {
//接受高并发容错
matchCharmUserScore.Score = diamondNum
//对应其等级
var matchCharmSetScoreGrade MatchCharmSetScoreGrade
if err := matchCharmUserScore.Db.Where("min_num <= ? AND max_num >= ?", matchCharmUserScore.Score, matchCharmUserScore.Score).First(&matchCharmSetScoreGrade).Error; err != nil {
return myerr.WrapErr(err)
}
matchCharmUserScore.Grade = matchCharmSetScoreGrade.Grade
return nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/match_e"
"hilo-group/myerr"
)
/**
* 用户财富分数
**/
type MatchWealthUserScore struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Score mysql.Num
Grade mysql.Num
}
/**
* 获取的分数同等级关系
**/
type MatchWealthSetScoreGrade struct {
mysql.Entity
*domain.Model `gorm:"-"`
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)
}
}
return wealthUserScore.Grade, wealthUserScore.Score, nil
}
func getMatchWealthUserScore(model *domain.Model, userId mysql.ID) (*MatchWealthUserScore, error) {
var matchWealthUserScore MatchWealthUserScore
if err := model.Db.Where(&MatchWealthUserScore{
UserId: userId,
}).First(&matchWealthUserScore).Error; err != nil {
if err == gorm.ErrRecordNotFound {
matchWealthUserScore = MatchWealthUserScore{
UserId: userId,
Score: 0,
Grade: 0,
}
} else {
return nil, err
}
}
matchWealthUserScore.Model = model
return &matchWealthUserScore, nil
}
/**
* 增加分数
**/
func (matchWealthUserScore *MatchWealthUserScore) updateScore(diamondNum mysql.Num) error {
//接受高并发容错
matchWealthUserScore.Score = diamondNum
//对应其等级
var matchWealthSetScoreGrade MatchWealthSetScoreGrade
if err := matchWealthUserScore.Db.Where("min_num <= ? AND max_num >= ?", matchWealthUserScore.Score, matchWealthUserScore.Score).First(&matchWealthSetScoreGrade).Error; err != nil {
return myerr.WrapErr(err)
}
matchWealthUserScore.Grade = matchWealthSetScoreGrade.Grade
return nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/res_e"
"hilo-group/domain/model/common"
"hilo-group/domain/model/count_m"
"hilo-group/domain/model/fruit_m"
"hilo-group/domain/model/gift_m"
"hilo-group/domain/model/luckybox_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"time"
)
//用户道具
type UserMedal struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
MedalId uint32
//MedalType res_m2.ResMedalType
//Scope res_m2.ResMedalScope
EndTime *time.Time
}
func GetUserMedalMerge(logger *logrus.Entry, db *gorm.DB, userId mysql.ID) ([]uint32, error) {
// 缓存拿
res, _ := common.GetUserMedalMergeCache(userId)
if res != nil {
return res, nil
}
// 数据库加载
result, err := GetUserMedal(db, userId)
if err != nil {
return nil, err
}
logger.Infof("GetUserMedalMerge, user %d, %+v", userId, result)
medalTypes, medalList, err := res_m.GetUserMedalLevelMap(db)
if err != nil {
return nil, err
}
logger.Infof("GetUserMedalLevelMap, user %d, medalMap %+v", medalTypes)
logger.Infof("GetUserMedalLevelMap, user %d, medalList %+v", medalList)
maxGrades := make(map[uint8]int, 0)
maxMedalIds := make(map[uint8]uint32, 0)
for _, m := range result {
mt := medalTypes[uint64(m)]
if mt > 0 {
if r, ok := medalList[mt]; ok {
for i, j := range r {
if j == uint64(m) {
if i+1 > maxGrades[mt] {
maxGrades[mt] = i + 1
maxMedalIds[mt] = m
logger.Infof("maxGrade of %d set to %d, due to %d", mt, i+1, m)
}
break
}
}
}
}
}
logger.Infof("maxGrade %+v", maxGrades)
logger.Infof("maxMedalIds %+v", maxMedalIds)
mIds := result
result = make([]uint32, 0)
for _, m := range mIds {
mt := medalTypes[uint64(m)]
if mt == 0 || maxMedalIds[mt] == m {
result = append(result, m)
}
}
// 写入缓存
common.SetUserMedalMergeCache(userId, result)
return result, nil
}
func GetUserMedal(db *gorm.DB, userId mysql.ID) ([]uint32, error) {
rows := make([]UserMedal, 0)
if err := db.Model(&UserMedal{}).Where("user_id = ? AND (end_time >= NOW() or end_time is null)", userId).Find(&rows).Error; err != nil {
return nil, err
}
result := make([]uint32, 0)
for _, i := range rows {
result = append(result, i.MedalId)
}
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
}
func BatchGetUserMedal(db *gorm.DB, userIds []mysql.ID) (map[uint64][]uint32, error) {
rows := make([]UserMedal, 0)
if err := db.Model(&UserMedal{}).Where("user_id IN ? and (end_time >= NOW() or end_time is null)", userIds).Find(&rows).Error; err != nil {
return nil, err
}
result := make(map[uint64][]uint32, 0)
for _, i := range rows {
if _, ok := result[i.UserId]; !ok {
result[i.UserId] = make([]uint32, 0)
}
result[i.UserId] = append(result[i.UserId], i.MedalId)
}
return result, nil
}
func (um *UserMedal) Create(db *gorm.DB, day int) error {
err := db.Clauses(clause.OnConflict{
DoUpdates: clause.Assignments(map[string]interface{}{
"end_time": gorm.Expr("DATE_ADD(GREATEST(end_time,NOW()), INTERVAL ? DAY);", day)}),
}).Create(um).Error
// 删除勋章缓存, 延迟删除
common.DelUserMedalMergeCacheDelay(um.UserId)
return err
}
func (um *UserMedal) Delete(db *gorm.DB) error {
err := db.Where(um).Delete(&UserMedal{}).Error
// 删除勋章缓存
common.DelUserMedalMergeCache(um.UserId)
return err
}
func GetUserMedalThreshold(model *domain.Model, userId mysql.ID, resMedalId mysql.ID) (uint64, error) {
resMedalObtain, err := res_m.ResMedalObtainGetByMedalId(model, resMedalId)
if err != nil {
return 0, err
}
if resMedalObtain == nil {
return 0, myerr.NewSysErrorF("res_m.ResMedalObtainGetByMedalId nil resMedalId:%v", resMedalId)
}
if resMedalObtain.Type == res_e.WealthResMedalObtainType {
wealthGrade, _, err := GetWealthGrade(model, userId)
if err != nil {
return 0, err
} else {
return uint64(wealthGrade), nil
}
} else if resMedalObtain.Type == res_e.CharmResMedalObtainType {
charmGrade, _, err := GetCharmGrade(model, userId)
if err != nil {
return 0, err
} else {
return uint64(charmGrade), nil
}
} else if resMedalObtain.Type == res_e.GiftResMedalObtainType {
sum, err := gift_m.SumSendGift(model, userId, resMedalObtain.ResGiftId)
if err != nil {
return 0, err
}
return uint64(sum), nil
} else if resMedalObtain.Type == res_e.BoomRocketResMedalObtainType {
s, err := rocket_m.GetUserTopCount(model.Db, userId)
if err != nil {
return 0, err
}
return uint64(s), nil
} else if resMedalObtain.Type == res_e.ActityResMedalObtainType {
wealthGrade, _, err := GetActityGrade(model, userId)
if err != nil {
return 0, err
} else {
return uint64(wealthGrade), nil
}
} else if resMedalObtain.Type == res_e.FruitKingResMedalObtainType {
diamond, err := fruit_m.SumAwardAll(model.Db, userId)
if err != nil {
return 0, err
} else {
return uint64(diamond), nil
}
} else if resMedalObtain.Type == res_e.LuckyBoxKingResMedalObtainType {
diamond, err := luckybox_m.GetSumLuckyboxDiamondV2(model, userId)
if err != nil {
return 0, err
} else {
return diamond, nil
}
} else if resMedalObtain.Type == res_e.VideoChatResMedalObtainType {
videoSeconds, err := count_m.GetVideoChatTimeTotal(model, userId)
if err != nil {
return 0, err
} else {
return uint64(videoSeconds / 60), nil // min
}
} else {
return 0, myerr.NewSysErrorF("GetUserMedalThreshold 类型错误 ResMedalType:%v", resMedalObtain.Type)
}
}
//增加勋章
func (user *User) AddPublicMedal(resMedalId mysql.ID) (*UserMedal, error) {
//判断是否已经拥有了该勋章
var n int64
if err := user.Db.Model(&UserMedal{}).Where(&UserMedal{
UserId: user.ID,
MedalId: uint32(resMedalId),
}).Count(&n).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if n > 0 {
return nil, myerr.NewWaringErrorF("用户 userId:%v, 已经获取了勋章 resMedalId:%v", user.ID, resMedalId)
}
resMedal, err := res_m.GetResMedalById(user.Model, resMedalId)
if err != nil {
return nil, err
}
//检查是否符合要求
threshold, err := GetUserMedalThreshold(user.Model, user.ID, resMedalId)
if err != nil {
return nil, err
}
if threshold < uint64(resMedal.Threshold) {
return nil, bizerr.UserMedalThresholdLimit
}
//
return &UserMedal{
Model: user.Model,
UserId: user.ID,
MedalId: uint32(resMedalId),
//MedalType: resMedal.Type,
//Scope: resMedal.Scope,
EndTime: nil,
}, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/property_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"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 GetUserPropertyOrErr(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 {
return nil, myerr.WrapErr(err)
}
userProperty.Model = model
return &userProperty, nil
}
//获取正在使用的座驾,不存在则位nil
/*func GetUserPropertyWithUsingNil(model *domain.Model, userId mysql.ID) (*UserProperty, error) {
userProperty := UserProperty{}
if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{
UserId: userId,
Using: property_m.YesUsing,
}).First(&userProperty).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, 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 (userProperty *UserProperty) Give(receiveUserId mysql.ID) (*UserProperty, *UserProperty, uint32, error) {
remainSecond := userProperty.EndTime.Unix() - time.Now().Unix()
if remainSecond <= 0 {
return nil, nil, 0, bizerr.UserPropertyHasEnd
}
receiveUserProperty, err := GetUserPropertyOrInit(userProperty.Model, receiveUserId, userProperty.PropertyId)
if err != nil {
return nil, nil, 0, err
}
receiveUserProperty, _ , err = receiveUserProperty.AddEndTime(property_e.Give, uint32(remainSecond), userProperty.UserId)
if err != nil {
return nil, nil, 0, err
}
_, err = addUserPropertyLog(userProperty.Model, userProperty.UserId, userProperty.PropertyId, property_e.Give, property_e.Del, nil, nil, userProperty.UserId)
if err != nil {
return nil, nil, 0, err
}
userProperty.SetDel()
return userProperty, receiveUserProperty, uint32(remainSecond), 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
}
func (up *UserProperty) BatchGet(db *gorm.DB, userIds []uint64) (map[uint64]uint64, error) {
rows := make([]UserProperty, 0)
if err := db.Model(up).
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
}
//用户道具日志
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
}
\ No newline at end of file
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/myerr"
)
type SuperManager struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
}
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 GetSuperManagerAll(model *domain.Model) ([]uint64, error) {
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
}
\ No newline at end of file
package user_m
import (
"git.hilo.cn/hilo-common/resource/config"
"strconv"
"strings"
)
var superUsers []uint64
func IsSuperUser(userId uint64) bool {
for _, i := range superUsers {
if i == userId {
return true
}
}
return false
}
func init() {
// 初始化超级用户
strUsers := strings.Split(config.GetConfigApp().SUPERUSER, ",")
for _, i := range strUsers {
if u, err := strconv.ParseUint(i, 10, 64); err == nil {
superUsers = append(superUsers, u)
}
}
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/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
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-group/_const/enum/user_e"
"hilo-group/myerr"
"time"
)
//用户Vip
type UserVip struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
ExpireAt time.Time //结束时间
Type user_e.UserVipType //来源类型
Platform mysql.Platform
VipSubscribeOrderId mysql.ID //最后的订单ID
}
// 检查某用户是否Vip
func (user *User) CheckVip() (bool, error) {
rows := make([]UserVip, 0)
err := user.Model.Db.Where("user_id = ? AND expire_at >= NOW()", user.ID).Find(&rows).Error
if err != nil {
return false, err
}
if len(rows) > 0 {
return true, nil
}
return false, nil
}
// 检查某用户是否Vip
func IsVip(userId uint64) (bool, *int64, error) {
uv, err := GetVip(mysql.Db, userId)
if err != nil {
return false, nil, err
}
if uv == nil {
return false, nil, nil
}
ts := uv.ExpireAt.Unix()
return true, &ts, nil
}
func GetVip(db *gorm.DB, userId uint64) (*UserVip, error) {
rows := make([]UserVip, 0)
err := db.Where("user_id = ? AND expire_at >= NOW()", userId).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) > 0 {
return &rows[0], 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
}
// 查询当前有效的vips(google)
func GetValidVipsGoogle(db *gorm.DB, userId uint64) (*UserVip, error) {
rows := make([]UserVip, 0)
err := db.Table("user_vip AS u").
Joins("INNER JOIN vip_subscribe_order_id AS s ON u.vip_subscribe_order_id = s.id").
Where("platform = ? and expire_at >= NOW()", user_e.Google).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) > 0 {
return &rows[0], nil
}
return nil, nil
}
//初始化用户Vip, 存在则抛出错误
func InitUserVip(model *domain.Model, userId uint64) (*UserVip, error) {
var n int64
if err := model.Db.Model(&UserVip{}).Where(&UserVip{
UserId: userId,
}).Count(&n).Error; err != nil {
return nil, myerr.WrapErr(err)
}
if n > 0 {
return nil, myerr.NewSysErrorF("该用户已经拥有/曾经拥有vip")
}
return &UserVip{
Model: model,
UserId: userId,
}, nil
}
//获取UserVip 不存在则抛出错误
func GetUserVip(model *domain.Model, userId uint64) (*UserVip, error) {
userVip := UserVip{}
if err := model.Db.Where(&UserVip{
UserId: userId,
}).First(&userVip).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, myerr.NewSysErrorF("userVip userId:%v 不存在", userId)
} else {
return nil, myerr.WrapErr(err)
}
}
userVip.Model = model
return &userVip, nil
}
func GetUserVipNil(model *domain.Model, userId uint64) (*UserVip, error) {
userVip := UserVip{}
if err := model.Db.Where(&UserVip{
UserId: userId,
}).First(&userVip).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userVip.Model = model
return &userVip, nil
}
//设置userVip来源于管理者
func (userVip *UserVip) SetOriginByMgr(expireAt time.Time) *UserVip {
userVip.Type = user_e.UserVipTypeGive
userVip.Platform = 0
userVip.VipSubscribeOrderId = 0
userVip.ExpireAt = expireAt
return userVip
}
//设置userVip来源于管理人
func (userVip *UserVip) AddDaysByMgr(days uint64) *UserVip {
userVip.Type = user_e.UserVipTypeGive
userVip.Platform = 0
userVip.VipSubscribeOrderId = 0
userVip.ExpireAt = userVip.ExpireAt.AddDate(0, 0, int(days))
return userVip
}
//删除userVip来源于管理人,支付购买的,无法删除
func (userVip *UserVip) DelByMgr() (*UserVip, error) {
if userVip.Type == user_e.UserVipTypeBuy {
return nil, myerr.NewSysError("真金白银购买的VIP不能删除")
} else {
if userVip.ExpireAt.After(time.Now()) {
userVip.ExpireAt = time.Now()
}
}
return userVip, nil
}
func MakeVip(db *gorm.DB, uvType user_e.UserVipType, userId uint64, expiredTime time.Time, subscribeOrderId uint64, platform mysql.Platform) error {
uv := UserVip{
UserId: userId,
ExpireAt: expiredTime,
Type: uvType,
Platform: platform,
VipSubscribeOrderId: subscribeOrderId,
}
return db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"type": uvType,
"platform": platform, // TODO:如何处理切换平台订阅的问题?
"expire_at": expiredTime,
"vip_subscribe_order_id": subscribeOrderId}),
}).Create(&uv).Error
}
func ExtendVip(db *gorm.DB, userId uint64, expireAt time.Time) error {
return db.Model(&UserVip{}).Where("user_id = ?", userId).Update("expire_at", expireAt).Error
}
// 检查一批用户中有没有一个是Vip
func CheckVipByUserIds(userIds []uint64) (bool, error) {
rows := make([]UserVip, 0)
err := mysql.Db.Where("user_id IN ?", userIds).Find(&rows).Error
if err != nil {
return false, err
}
now := time.Now()
for _, i := range rows {
if i.ExpireAt.After(now) {
return true, nil
}
}
return false, nil
}
type VipSubscribeApple struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Receipt mysql.Str
TransactionId mysql.Str
OriginalTransactionId mysql.Str
}
func (v *VipSubscribeApple) Get() (*VipSubscribeApple, error) {
rows := make([]VipSubscribeApple, 0)
err := mysql.Db.Where(v).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) <= 0 {
return nil, nil
}
return &rows[0], nil
}
// 添加ios支付凭证
// 1. 检查旧订单(同origin_transaction_id)
// 2. 处理完全相同的transaction_id订单,更新对应的user_id
// 3. 若无相同transaction_id,则插入新的记录
// return: vip_subscribe_apple的唯一id, 旧的单子, error
func (v *VipSubscribeApple) Add(model *domain.Model) (uint64, []VipSubscribeApple, error) {
// 检查,订单是否已经存在
// 订阅的单子,需要看original_transaction_id判断
var olds []VipSubscribeApple
if err := model.Db.Model(&VipSubscribeApple{}).Where(&VipSubscribeApple{
//TransactionId: v.TransactionId,
OriginalTransactionId: v.OriginalTransactionId,
}).Find(&olds).Error; err != nil {
return 0, nil, myerr.WrapErr(err)
}
for _, old := range olds {
// 完全是拿旧的transactionId
if old.TransactionId == v.TransactionId {
if err := model.Db.Model(&VipSubscribeApple{}).Where("transaction_id = ?", v.TransactionId).Update("user_id", v.UserId).Error; err != nil {
return 0, nil, err
} else {
return old.ID, olds, nil
}
}
}
if err := model.Db.Model(&VipSubscribeApple{}).Create(&v).Error; err != nil {
return 0, nil, myerr.WrapErr(err)
}
return v.ID, olds, nil
}
type VipSubscribeGoogle struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
PackageName mysql.Str
SubscriptionID mysql.Str
PurchaseToken mysql.Str
}
func GetGoogleSubscribe(model *domain.Model, packageName, subscriptionID, purchaseToken mysql.Str) (*VipSubscribeGoogle, error) {
q := VipSubscribeGoogle{
Model: model,
PackageName: packageName, SubscriptionID: subscriptionID, PurchaseToken: purchaseToken}
return q.Get()
}
func BatchGetGoogleSubscribe(db *gorm.DB, ids []uint64) ([]VipSubscribeGoogle, error) {
rows := make([]VipSubscribeGoogle, 0)
err := db.Model(&VipSubscribeGoogle{}).Where("id IN ?", ids).Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func (v *VipSubscribeGoogle) Get() (*VipSubscribeGoogle, error) {
rows := make([]VipSubscribeGoogle, 0)
err := v.Db.Where(v).Find(&rows).Error
if err != nil {
return nil, err
}
if len(rows) <= 0 {
return nil, nil
}
return &rows[0], nil
}
func (v *VipSubscribeGoogle) Add() (uint64, error) {
err := v.Db.Model(&VipSubscribeGoogle{}).Create(&v).Error
if err == nil {
return v.ID, nil
}
return 0, err
}
type GoogleSubscribeState struct {
mysql.Entity
*domain.Model `gorm:"-"`
PurchaseToken mysql.Str
OrderId mysql.Str
CountryCode mysql.Str
PriceAmountMicros int64
PriceCurrencyCode mysql.Str
StartTimeMillis int64
ExpiryTimeMillis int64
AutoRenewing bool
LinkedPurchaseToken mysql.Str
PaymentState int64
CancelReason int64
UserCancellationTimeMillis int64
}
func (gss *GoogleSubscribeState) Set() (uint64, error) {
err := gss.Db.Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(gss).Error
if err == nil {
return gss.ID, nil
}
return 0, err
}
package visit_m
import "hilo-group/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-group/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 group_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/group_m"
"strconv"
"time"
)
type GroupService struct {
svc *domain.Service
}
func NewGroupService(myContext *mycontext.MyContext) *GroupService {
svc := domain.CreateService(myContext)
return &GroupService{svc}
}
// 取本周最高的扶持等级 fixme:删除这个过渡函数
func (s *GroupService) GetWeekMaxSupportLevelMap() (map[string]uint8, error) {
return s.GetSupportLevelMap(time.Now().AddDate(0, 0, -group_e.SUPPORT_LEVEL_PERIOD_DAY))
}
func (s *GroupService) GetSupportLevelMap(now time.Time) (map[string]uint8, error) {
model := domain.CreateModel(s.svc.CtxAndDb)
_, _, period := group_m.GetSupportLevelTime(now)
levels, err := GetAllSupportLevel(model, period)
if err != nil {
return nil, err
}
model.Log.Debugf("GetSupportLevelMap, GET %s: %v", period, levels)
result := make(map[string]uint8, 0)
if len(levels) > 0 {
for g, l := range levels {
le, err := strconv.ParseUint(l, 10, 8)
if err == nil {
result[g] = uint8(le)
}
}
} else {
result, err = group_m.GetAllGroupSupportResult(model.Db, period)
if err == nil {
ret, err := SaveAllSupportLevel(model, period, result)
model.Log.Infof("GetSupportLevelMap SAVE ret = %d, err: %v", ret, err)
}
}
return result, nil
}
func SaveAllSupportLevel(model *domain.Model, date string, levels map[string]uint8) (int64, error) {
values := make(map[string]interface{}, 0)
for g, l := range levels {
if l > 0 {
values[g] = l
}
}
if len(values) <= 0 {
return 0, nil
}
key := redis_key.GetPrefixSupportLevel(date)
ret, err := model.Redis.HSet(model, key, values).Result()
if err == nil {
// 设置一个TTL保险一些 TODO: 可以优化,保证数据总是有的
ttl := time.Hour
if !config.AppIsRelease() {
ttl = time.Minute
}
model.Redis.Expire(model, key, ttl)
}
return ret, err
}
func GetAllSupportLevel(model *domain.Model, date string) (map[string]string, error) {
key := redis_key.GetPrefixSupportLevel(date)
return model.Redis.HGetAll(model, key).Result()
}
package group_s
import (
"git.hilo.cn/hilo-common/domain"
"hilo-group/_const/enum/group_e"
"hilo-group/domain/model/group_m"
)
// 创建群组
func (s *GroupService) CreateGroup(userId uint64, g *group_m.GroupInfo) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
if err := group_m.CreateGroup(model, g); err != nil {
return err
}
if err := group_m.CreateGroupRole(model, g.ImGroupId, userId, group_e.GROUP_OWNER); err != nil {
return err
}
return nil
})
}
...@@ -6,11 +6,13 @@ replace git.hilo.cn/hilo-common => ../hilo-common ...@@ -6,11 +6,13 @@ replace git.hilo.cn/hilo-common => ../hilo-common
require ( require (
git.hilo.cn/hilo-common v0.0.0-00010101000000-000000000000 // indirect git.hilo.cn/hilo-common v0.0.0-00010101000000-000000000000 // indirect
github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src v0.0.0-20200910100525-12b7f1b63a6a // indirect
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/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // 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/bluele/gcache v0.0.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
...@@ -56,11 +58,16 @@ require ( ...@@ -56,11 +58,16 @@ require (
github.com/sirupsen/logrus v1.7.0 // indirect github.com/sirupsen/logrus v1.7.0 // indirect
github.com/swaggo/gin-swagger v1.2.0 // indirect github.com/swaggo/gin-swagger v1.2.0 // indirect
github.com/swaggo/swag v1.6.7 // indirect github.com/swaggo/swag v1.6.7 // 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-20220715151400-c0bba94af5f8 // 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-20190907020128-2ca718005c18 // 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 google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.63.2 // 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
......
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 h1:+/ILLIcuKbrW4kyQ0V574aV9skXRivrcmlg0IBk7apY=
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=
...@@ -9,14 +13,26 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV ...@@ -9,14 +13,26 @@ 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/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/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/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/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
...@@ -24,6 +40,12 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC ...@@ -24,6 +40,12 @@ 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=
...@@ -68,14 +90,32 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC ...@@ -68,14 +90,32 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
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 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/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.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 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.6.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
...@@ -170,8 +210,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE ...@@ -170,8 +210,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
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=
...@@ -185,6 +227,8 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH ...@@ -185,6 +227,8 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
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/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/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=
...@@ -192,6 +236,12 @@ github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM= ...@@ -192,6 +236,12 @@ github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM=
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/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 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
...@@ -202,13 +252,23 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs ...@@ -202,13 +252,23 @@ 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=
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/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-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/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-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=
...@@ -217,11 +277,17 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL ...@@ -217,11 +277,17 @@ 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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-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=
...@@ -236,6 +302,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w ...@@ -236,6 +302,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
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-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-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-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
...@@ -246,6 +313,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= ...@@ -246,6 +313,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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-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 h1:/mJ+GKieZA6hFDQGdWZrjj4AXPl5ylY+5HusG80roy0= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b h1:/mJ+GKieZA6hFDQGdWZrjj4AXPl5ylY+5HusG80roy0=
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=
...@@ -254,6 +325,31 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 h1:xFbv3LvlvQAmbNJFCBKRv1C ...@@ -254,6 +325,31 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 h1:xFbv3LvlvQAmbNJFCBKRv1C
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/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-20191204190536-9bdfabe68543/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/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-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
...@@ -266,11 +362,15 @@ gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= ...@@ -266,11 +362,15 @@ 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/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.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
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.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=
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=
...@@ -20,30 +20,41 @@ var ( ...@@ -20,30 +20,41 @@ 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{})
// 游戏 // 礼物
GameInvalidParameter = myerr.NewGameError(10002, "invalid parameter") ResGiftNoUser = myerr.NewBusinessCode(5001, "GiftDetail is gone", myerr.BusinessData{}) // 礼物已经下架
GameTokenInvalid = myerr.NewGameError(1004, "user token invalid") ResHeadwearDiamondNoUse = myerr.NewBusinessCode(5003, "Headwear can not buy", myerr.BusinessData{}) //头饰不能买
GameTokenExpire = myerr.NewGameError(1005, "user token expire") ResPropertyDiamondNoUse = myerr.NewBusinessCode(5004, "Property can not buy", myerr.BusinessData{}) //头饰不能买
UserMedalThresholdLimit = myerr.NewBusinessCode(9006, "勋章条件未达到", myerr.BusinessData{})
UserHeadwearHasEnd = myerr.NewBusinessCode(9014, "用户头饰已经过期, 不能赠送", myerr.BusinessData{})
UserPropertyHasEnd = myerr.NewBusinessCode(9015, "用户座驾已经过期, 不能赠送", myerr.BusinessData{})
// 麦位
GroupMicNoPermission = myerr.NewBusinessCode(12000, "Mic has no permission to mic", myerr.BusinessData{}) // 麦位没有操作的权限
GroupMicNoUser = myerr.NewBusinessCode(12002, "No one on Mic", myerr.BusinessData{}) // 麦位上没有人
GroupMicLock = myerr.NewBusinessCode(12003, "Mic is locked", myerr.BusinessData{}) // 麦位加锁了
GroupMicHasUser = myerr.NewBusinessCode(12004, "Mic occupied", myerr.BusinessData{}) // 麦位中已经有人了
GroupMicUserHasIn = myerr.NewBusinessCode(12006, "Already on Mic", myerr.BusinessData{}) // 你已经在别的麦位上了
GroupMicNoYou = myerr.NewBusinessCode(12007, "Not on Mic", myerr.BusinessData{}) // 你不在该麦位上
GroupInfoMicClosed = myerr.NewBusinessCode(12009, "The Group does not open the mic positions", myerr.BusinessData{})
// 群组 // 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群 GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
NoPrivileges = myerr.NewBusinessCode(14004, "Not enough permission", myerr.BusinessData{}) // 操作权限不够
// 游戏服务的错误码,6位,50XXX GroupIsBanned = myerr.NewBusinessCode(14011, "group is banned by ", myerr.BusinessData{}) // 群已经被管理员封禁
GameAddNoPermissions = myerr.NewBusinessCode(50100, "Only room administrators can create users", myerr.BusinessData{}) // 权限不足 GroupCreateLimitReached = myerr.NewBusinessCode(14014, "Create group limit reached", myerr.BusinessData{}) // 你创建的群组数已达上限
GameAddNotOnMic = myerr.NewBusinessCode(50101, "Need on mic", myerr.BusinessData{}) // 需要在麦上才能创建、加入游戏 GroupCustomThemeLimit = myerr.NewBusinessCode(14020, "Group Custom Theme Limit", myerr.BusinessData{}) //群主题定制数量只能是5个
GameHaveNoEnd = myerr.NewBusinessCode(50102, "Group user have no end", myerr.BusinessData{}) // 房间还有未结束的游戏
GameNotFound = myerr.NewBusinessCode(50103, "Game not found", myerr.BusinessData{}) // // 家族
GameStart = myerr.NewBusinessCode(50104, "Gaming", myerr.BusinessData{}) // GroupPowerHasJoinOther = myerr.NewBusinessCode(15001, "You already have joined power, please exit first", myerr.BusinessData{}) // 已经加入了其它国家势力
GameAlreadyJoin = myerr.NewBusinessCode(50105, "Already Joined", myerr.BusinessData{}) // 已经加入了游戏 GroupPowerHasJoinMy = myerr.NewBusinessCode(15002, "You already have joined power, please exit first", myerr.BusinessData{}) // 已经加入了该国家势力
GameNotJoin = myerr.NewBusinessCode(50106, "Not Join user", myerr.BusinessData{}) // 还未加入游戏 GroupPowerOwnerLeave = myerr.NewBusinessCode(15003, "power owner cannot exit", myerr.BusinessData{}) // 势力主不能退出
GameCannotClose = myerr.NewBusinessCode(50107, "Have no power to close user", myerr.BusinessData{}) // 没有权限关闭游戏 GroupPowerNoOwner = myerr.NewBusinessCode(15005, "power owner not exits or unique", myerr.BusinessData{}) // 国家势力主不存在或不唯一
GameCloseGaming = myerr.NewBusinessCode(50108, "Can't close a user in progress", myerr.BusinessData{}) // 不能关闭进行中的游戏 GroupPowerStayTooShort = myerr.NewBusinessCode(15006, "You joined this power not more than 10 days ago", myerr.BusinessData{}) // 加入国家势力不超过10天
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{}) // 已经加入了其他房间的游戏 NobleNoMicSpeechCloseLevel5 = myerr.NewBusinessCode(21001, "Can't mute the King", myerr.BusinessData{}) //无法禁言贵族5
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{}) // 结算修改错误 OfficialStaffLimit = myerr.NewBusinessCode(22001, "Operation failed", myerr.BusinessData{})
GameCloseWrong = myerr.NewBusinessCode(50115, "Game close wrong", myerr.BusinessData{}) // 关闭错误
GameJoinFailed = myerr.NewBusinessCode(50116, "Join failed", myerr.BusinessData{}) // 加入失败
) )
...@@ -80,3 +80,30 @@ func GetUserIdLang(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, st ...@@ -80,3 +80,30 @@ func GetUserIdLang(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, st
} }
return 0, "", bizerr.ParaMissing return 0, "", bizerr.ParaMissing
} }
// 同时获取userId和externalId, nick, avatar, country
func GetUserEx(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, string, string, string, error) {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
externalId, ok1 := c.Get(mycontext.EXTERNAL_ID)
nick, ok2 := c.Get(mycontext.NICK)
avatar, ok3 := c.Get(mycontext.AVATAR)
country, ok4 := c.Get(mycontext.COUNTRY)
ok := ok1 && ok2 && ok3 && ok4
if ok {
return userId, externalId.(string), nick.(string), avatar.(string), country.(string), nil
} else {
//var user user_m.User
//if err := mysql.Db.First(&user, userId).Error; err != nil {
// return 0, "", "", "", "", bizerr.ExternalIdNoExist
//}
user, err := user_c.GetUserTinyById(domain.CreateModelContext(myContext), userId)
if err != nil {
return 0, "", "", "", "", bizerr.ExternalIdNoExist
}
return userId, user.ExternalId, user.Nick, user.Avatar, user.Country, nil
}
}
return 0, "", "", "", "", bizerr.ParaMissing
}
...@@ -3,9 +3,11 @@ package resp ...@@ -3,9 +3,11 @@ package resp
import ( import (
"encoding/json" "encoding/json"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-group/myerr" "hilo-group/myerr"
"net/http" "net/http"
"time"
) )
type Response struct { type Response struct {
...@@ -16,13 +18,6 @@ type Response struct { ...@@ -16,13 +18,6 @@ type Response struct {
Data interface{} `json:"data"` // 数据 Data interface{} `json:"data"` // 数据
} }
type GameResponse struct {
RetCode uint16 `json:"ret_code"`
RetMsg string `json:"ret_msg"`
SdkErrorCode uint16 `json:"sdk_error_code"`
Data interface{} `json:"data"`
}
/** /**
* HTTP输出json信息 * HTTP输出json信息
* param: *gin.Context * param: *gin.Context
...@@ -42,30 +37,6 @@ func ResponseOk(c *gin.Context, data interface{}) { ...@@ -42,30 +37,6 @@ func ResponseOk(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
func GameResponseOk(c *gin.Context, data interface{}) {
// always return http.StatusOK
response := GameResponse{
RetCode: 0,
RetMsg: myerr.GetSuccessMsg(),
SdkErrorCode: 0,
Data: data,
}
printResponseBody(c, &response)
c.JSON(http.StatusOK, response)
}
func GameResponseFail(c *gin.Context, err *myerr.GameError) {
// always return http.StatusOK
response := GameResponse{
RetCode: err.Code(),
RetMsg: err.Error(),
SdkErrorCode: err.Code(),
Data: nil,
}
printResponseBody(c, &response)
c.JSON(http.StatusOK, response)
}
func ResponseWaring(c *gin.Context, waringError *myerr.WaringError) { func ResponseWaring(c *gin.Context, waringError *myerr.WaringError) {
response := Response{ response := Response{
Code: waringError.GetCode(), Code: waringError.GetCode(),
...@@ -136,3 +107,31 @@ func printResponseBody(c *gin.Context, response interface{}) { ...@@ -136,3 +107,31 @@ func printResponseBody(c *gin.Context, response interface{}) {
mycontext.CreateMyContext(c.Keys).Log.Error("request rsp body Marshal fail traceId:%v, err:%v", traceId, err) mycontext.CreateMyContext(c.Keys).Log.Error("request rsp body Marshal fail traceId:%v, err:%v", traceId, err)
} }
} }
type Page struct {
Total uint `json:"total"`
Index int `json:"index"`
Data interface{} `json:"data"`
}
func ResponsePageOk(c *gin.Context, data interface{}, total uint, index int) {
// always return http.StatusOK
response := Response{
Code: myerr.GetSuccessCode(),
Message: myerr.GetSuccessMsg(),
OperationMessage: myerr.GetSuccessMsg(),
Data: Page{
Total: total,
Index: index,
Data: data,
},
}
printResponseBody(c, &response)
beginTime := time.Now()
c.JSON(http.StatusOK, response)
timeDiff := time.Now().Sub(beginTime)
traceId, _ := c.Get(mycontext.TRACEID)
mylogrus.MyLog.Infof("ResponsePageOk traceId: %s, JSON takes %v", traceId, timeDiff)
}
package group_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-group/_const/enum/gift_e"
"hilo-group/_const/enum/group_e"
"hilo-group/cv/gift_cv"
"hilo-group/cv/group_cv"
"hilo-group/cv/group_power_cv"
"hilo-group/cv/medal_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m"
"hilo-group/domain/service/group_s"
"hilo-group/req"
"hilo-group/resp"
"sort"
"strconv"
"time"
)
// @Tags 群组
// @Summary 查询热门群组
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} cv.PopularGroupInfo
// @Router /v1/imGroup/popular [get]
func GetPopularGroups(c *gin.Context) (*mycontext.MyContext, error) {
start := time.Now()
myContext := mycontext.CreateMyContext(c.Keys)
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
myUserId, _, _, _, myCountry, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
/* 2022-06-30 老板说先不分区
regions, err := res_m.GetAllLangRegion(model)
if err != nil {
return myContext, err
}
myRegion := regions[myCountry]
model.Log.Infof("GetPopularGroups: user %d, name = %s, country = %s, region = %s", myUserId, myNick, myCountry, myRegion)
*/
bannedGroups, err := group_m.GetBannedGroupsMap(model)
if err != nil {
return myContext, err
}
gs := group_m.GroupSetting{IsHidden: true}
hiddenGroups, _ := gs.GetHidden(model.Db)
if err != nil {
return myContext, err
}
model.Log.Infof("GetPopularGroups: page size = %d, page index = %d, banMap %v, hidenMap %v,cost:%v", pageSize, pageIndex, bannedGroups, hiddenGroups, time.Now().Sub(start))
hotGroupList := make([]group_m.GroupInfo, 0)
// 获取麦上有人的所有群组及麦上人数 v10,只有麦上有人的能上热门
micGroupNum, err := group_m.GetMicHasInGroupNum(model)
if err != nil {
return myContext, err
}
model.Log.Infof("GetMicHasInGroupNum: cost %v", time.Now().Sub(start))
banCount := 0
hiddenCount := 0
groupIds := make([]string, 0)
for i := range micGroupNum {
// 过滤掉被封禁的群
if bannedGroups[i] != 0 {
banCount++
continue
}
// 过滤掉被隐藏的群
if _, exist := hiddenGroups[i]; exist {
hiddenCount++
continue
}
groupIds = append(groupIds, i)
}
model.Log.Infof("GetPopularGroups, micGroupNum: %v, banned %d, hidden %d,cost:%v", micGroupNum, banCount, hiddenCount, time.Now().Sub(start))
// 3. 处理置顶群
topGroupIds, err := getTopGroups(model, bannedGroups, hiddenGroups)
if err != nil {
return myContext, err
}
sortedGroupIds := make([]string, 0)
for _, i := range groupIds {
found := false
for _, j := range topGroupIds {
if i == j {
found = true
break
}
}
// 已经在置顶群范围内的跳过
if !found {
sortedGroupIds = append(sortedGroupIds, i)
}
}
groupIds = append(groupIds, topGroupIds...)
groups, err := group_m.BatchGetGroupInfo(model, groupIds)
if err != nil {
return myContext, err
}
for _, i := range topGroupIds {
/* 2022-06-30 老板说先不分区 // 置顶只对同语言区的生效
if myRegion != regions[topGroupInfo[i].Country] {
continue
}
*/
// 已经置顶的,直接进队列,不再参与排序
hotGroupList = append(hotGroupList, groups[i])
//delete(groupIds, i)
}
// for pretty log
//logstr := ""
//for _, i := range hotGroupList {
//logstr += " " + i.ImGroupId
//}
//logstr += " |"
countryScore := make(map[string]int)
if len(myCountry) > 0 {
for _, i := range sortedGroupIds {
if myCountry == groups[i].Country {
countryScore[i] = 1
} else {
countryScore[i] = 0
}
}
}
model.Log.Infof("GetPopularGroups, countryScore[*]: %v,cost:%v", countryScore, time.Now().Sub(start))
now := time.Now()
bTime := now.Add(-time.Minute * 30)
g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType}
diamonds, err := g.GetRangeConsumeSummaryV2(bTime, now, groupIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetPopularGroups, diamonds in 30 mins: %v,cost:%v", diamonds, time.Now().Sub(start))
visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
if err != nil {
return myContext, err
}
// 排序优先级2022-07-25版本
sort.Slice(sortedGroupIds, func(i, j int) bool {
gi := sortedGroupIds[i]
gj := sortedGroupIds[j]
// 1、老板说,优化按国家
if countryScore[gi] > countryScore[gj] {
return true
} else if countryScore[gi] < countryScore[gj] {
return false
}
// 2、按麦上人数多少排序
if micGroupNum[gi] > micGroupNum[gj] {
return true
} else if micGroupNum[gi] < micGroupNum[gj] {
return false
}
// 3、麦上人数相同,按30分钟内送礼钻石数排序
if diamonds[gi] > diamonds[gj] {
return true
} else if diamonds[gi] < diamonds[gj] {
return false
}
// 4、按热度递减排序
if visitCount[gi] > visitCount[gj] {
return true
} else if visitCount[gi] < visitCount[gj] {
return false
}
// * Final resort: 群组CODE,短号优先,然后按字母序
return len(groups[gi].Code) < len(groups[gj].Code) || len(groups[gi].Code) == len(groups[gj].Code) && groups[gi].Code < groups[gj].Code
})
// for pretty log
// * 同国家 ^ 麦上有人 + 开放群 - 需要等级的群
for _, g := range sortedGroupIds {
hotGroupList = append(hotGroupList, groups[g])
//prefix := " "
//if countryScore[g] == 0 {
//prefix += "*"
//}
//logstr += prefix + g + ":" + groups[g].Code + ":" + strconv.Itoa(int(micGroupNum[g])) +
// ":" + strconv.FormatUint(diamonds[g], 10) + ":" + strconv.Itoa(int(visitCount[g]))
}
total := len(hotGroupList)
model.Log.Infof("GetPopularGroups: hotGroupList size = %d,cost:%v", total, time.Now().Sub(start))
result := make([]group_cv.PopularGroupInfo, 0)
beginPos := pageSize * (pageIndex - 1)
endPos := pageSize * pageIndex
if beginPos < total {
if endPos > total {
endPos = total
}
groupIds := make([]string, 0)
owners := make([]uint64, 0)
for _, i := range hotGroupList[beginPos:endPos] {
groupIds = append(groupIds, i.ImGroupId)
owners = append(owners, i.Owner)
}
powerIds, powerNames, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return myContext, err
}
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return myContext, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return myContext, err
}
//roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds)
//if err != nil {
// return myContext, err
//}
model.Log.Infof("GetPopularGroups: final start = %d, end = %d, groupIds %v,cost:%v", beginPos, endPos, groupIds, time.Now().Sub(start))
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, err
}
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds)
if err != nil {
return myContext, err
}
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
for _, i := range hotGroupList[beginPos:endPos] {
micUsers := make([]user_cv.CvUserTiny, 0)
var maxStage *uint16 = nil
if s, ok := maxStageMap[i.ImGroupId]; ok {
maxStage = &s
}
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[i.ImGroupId]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
}
}
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, i.ImGroupId)
if err != nil {
model.Log.Infof("GetPopularGroups: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
var password *string = nil
if len(i.Password) > 0 && i.Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
result = append(result, group_cv.PopularGroupInfo{
GroupInfo: group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: i.TxGroupId,
Name: i.Name,
Introduction: i.Introduction,
Notification: i.Notification,
FaceUrl: i.FaceUrl,
Code: i.Code,
CountryIcon: countryInfo[i.Country],
Password: password,
SupportLevel: supportLevels[i.ImGroupId],
GroupInUserDuration: visitCount[i.ImGroupId],
MicNumType: int(i.MicNumType),
GroupMedals: medals,
},
HasOnMic: true,
GroupPowerId: powerIds[i.Owner],
GroupPowerName: powerNames[i.Owner],
},
MicUsers: micUsers,
RoomUserCount: uint(roomCount[i.ImGroupId]),
MaxStage: maxStage,
GameTypes: games[i.TxGroupId],
})
}
}
resp.ResponsePageOk(c, result, uint(total), pageIndex)
return myContext, nil
}
func getTopGroups(model *domain.Model, bannedGroups map[string]uint64, hiddenGroups map[string]struct{}) ([]string, error) {
topGroups, err := group_m.GroupTopGetAll(model)
if err != nil {
return nil, err
}
result := make([]string, 0)
for _, i := range topGroups {
// 过滤掉被封禁的群。理论上是不需要的,因为被封禁的不会被置顶。这里只是为了保险
if bannedGroups[i] != 0 {
continue
}
// 过滤掉被隐藏的群
if _, exist := hiddenGroups[i]; exist {
continue
}
result = append(result, i)
}
return result, nil
}
type GetLatestGroupsReq struct {
PageSize int `form:"pageSize"` // binding:"min=1"
PageIndex int `form:"pageIndex"`
LastId int `form:"lastId"`
}
// @Tags 群组
// @Summary 查询最新群组
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Param lastId query int false "上一页列表的最后一个id,避免分页重复 默认:0" default(1)
// @Success 200 {object} cv.LatestGroupInfo
// @Router /v1/imGroup/latest [get]
func GetLatestGroups(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
request := &GetLatestGroupsReq{}
err := c.ShouldBindQuery(request)
if err != nil {
return myContext, err
}
if request.PageSize <= 0 {
request.PageSize = 10
}
if request.PageIndex <= 0 {
request.PageIndex = 1
}
// 上一页最后一个id, 避免分页变化数据重复
if request.LastId <= 0 {
request.LastId = 0
}
//offset := (req.PageIndex - 1) * req.PageSize
model := domain.CreateModelContext(myContext)
micGroupNum, err := group_m.GetMicHasInGroupNum(model)
if err != nil {
return myContext, err
}
gids := make([]string, 0)
for i, _ := range micGroupNum {
gids = append(gids, i)
}
// 获取最新群组列表
groupInfos, err := group_m.GetLatestGroupInfos(model, request.PageSize, request.LastId, gids)
if err != nil {
return myContext, err
}
// 提取id
groupIds := make([]string, 0, len(groupInfos))
for _, group := range groupInfos {
groupIds = append(groupIds, group.ImGroupId)
}
// 获取国家信息
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
// 获取本周最高的扶持等级
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
// 用户id
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
// 获取房间浏览数量
visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
if err != nil {
return myContext, err
}
// 获取群势力信息
owners := make([]uint64, 0)
for _, group := range groupInfos {
owners = append(owners, group.Owner)
}
powerIds, powerNames, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return myContext, err
}
// 获取群勋章信息
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return myContext, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return myContext, err
}
// 获取房间人数信息
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, err
}
// 获取火箭信息
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds)
if err != nil {
return myContext, err
}
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
result := make([]*group_cv.LatestGroupInfo, 0)
for _, group := range groupInfos {
micUsers := make([]user_cv.CvUserTiny, 0)
// 密码应该是一直为空?
var password *string = nil
if len(group.Password) > 0 && group.Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
// 勋章信息
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[group.ImGroupId]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
}
}
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, group.ImGroupId)
if err != nil {
model.Log.Infof("GetLatestGroups: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
// 最大的火箭
var maxStage *uint16 = nil
if s, ok := maxStageMap[group.ImGroupId]; ok {
maxStage = &s
}
result = append(result, &group_cv.LatestGroupInfo{
GroupInfo: group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
Id: group.Id,
GroupId: group.TxGroupId,
Name: group.Name,
Introduction: group.Introduction,
Notification: group.Notification,
FaceUrl: group.FaceUrl,
Code: group.Code,
CountryIcon: countryInfo[group.Country],
Password: password,
SupportLevel: supportLevels[group.ImGroupId],
GroupInUserDuration: visitCount[group.ImGroupId],
MicNumType: int(group.MicNumType),
GroupMedals: medals,
},
HasOnMic: true,
GroupPowerId: powerIds[group.Owner],
GroupPowerName: powerNames[group.Owner],
},
MicUsers: micUsers,
RoomUserCount: uint(roomCount[group.ImGroupId]),
MaxStage: maxStage,
GameTypes: games[group.TxGroupId],
})
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 查询推荐的群组(version>=2.19)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} cv.PopularGroupInfo
// @Router /v1/imGroup/recommended [get]
func GetRecommendGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
model := domain.CreateModelContext(myContext)
bannedGroups, err := group_m.GetBannedGroupsMap(model)
if err != nil {
return myContext, err
}
//noPwdGroups, err := group_m.FindNoPasswordGroups(model)
//if err != nil {
// return myContext, err
//}
// 获取麦上有人的所有群组及麦上人数
micGroupNum, err := group_m.GetMicHasInGroupNum(model)
if err != nil {
return myContext, err
}
var micGroupIds []string
for groupId := range micGroupNum {
micGroupIds = append(micGroupIds, groupId)
}
model.Log.Infof("GetRecommendGroups, micGroupNum : %v", micGroupNum)
noPwdGroups, err := group_m.FindNoPasswordGroupsV2(model, micGroupIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetRecommendGroups: noPwdGroups = %d, bannedGroups = %d", len(noPwdGroups), len(bannedGroups))
groupIds := make([]string, 0)
banCount := 0
for _, v := range noPwdGroups {
if _, ok := micGroupNum[v.ImGroupId]; ok {
if bannedGroups[v.ImGroupId] != 0 {
banCount++
} else {
groupIds = append(groupIds, v.ImGroupId)
}
}
}
model.Log.Infof("GetRecommendGroups: size = %d, banned %d", len(groupIds), banCount)
myService := domain.CreateService(myContext)
result, _, err := group_cv.BuildJoinedGroupInfo(myService, 0, groupIds, group_e.GROUP_RECOMMEND_SIZE, 1)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, result)
return myContext, nil
}
package group_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/sdk/agora"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/_const/redis_key/group_k"
"hilo-group/cv/billboard_cv"
"hilo-group/cv/gift_cv"
"hilo-group/cv/group_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req"
"hilo-group/resp"
"sort"
"strings"
"time"
)
type CreateGroupRsp struct {
ImGroupId string `json:"imGroupId"`
Code string `json:"code"`
}
// @Tags 群组
// @Summary 建群
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param name formData string false "群名"
// @Param introduction formData string false "群简介"
// @Param notification formData string false "群公告"
// @Param faceUrl formData string false "群头像 URL"
// @Success 200 {object} CreateGroupRsp
// @Router /v1/imGroup/group [post]
func CreateGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
if lock := redisCli.Lock(group_k.GetGroupLockKey(userId), time.Second*5); !lock {
return myContext, bizerr.ReqTooFrequent
}
model := domain.CreateModelContext(myContext)
user, err := user_m.GetUser(model, userId)
if err != nil {
return myContext, err
}
// Kludge: 不支持的语言,强行修正为英语,以保证建群成功
if c, err := res_m.GetCountryByLanguage(model, user.Language); err != nil || c == nil {
user.Language = utils.DEFAULT_LANG
}
// 群组的头像默认为用户头像,群组的名称默认为用户昵称,群简介默认为“s%的群组”,群公告默认为“欢迎来到Hilo”
name := c.PostForm("name")
if len(name) <= 0 {
text := res_m.ResMultiText{MsgId: msg_e.MSG_ID_GROUP_NAME, Language: user.Language}
if text.Get(model.Db) == nil {
name = strings.ReplaceAll(text.Content, "{nick}", user.Nick)
}
}
introduction := c.PostForm("introduction")
if len(introduction) <= 0 {
text := res_m.ResMultiText{MsgId: msg_e.MSG_ID_GROUP_INTRODUCTION, Language: user.Language}
if text.Get(model.Db) == nil {
introduction = strings.ReplaceAll(text.Content, "{nick}", user.Nick)
}
}
notification := c.PostForm("notification")
if len(notification) <= 0 {
text := res_m.ResMultiText{MsgId: msg_e.MSG_ID_GROUP_NOTIFICATION, Language: user.Language}
if text.Get(model.Db) == nil {
notification = strings.ReplaceAll(text.Content, "{nick}", user.Nick)
}
}
faceUrl := c.PostForm("faceUrl")
if len(faceUrl) <= 0 {
faceUrl = user.Avatar
}
myGroups, err := group_m.FindGroupByOwner(model, userId)
if err != nil {
return nil, err
}
// Kludge: 对超级号放开建群限制
if !user_m.IsSuperUser(userId) && len(myGroups) >= group_e.GROUP_CREATE_LIMIT {
return myContext, bizerr.GroupCreateLimitReached
}
code := group_m.GenerateGroupCode(group_e.GROUP_DEFAULT_CODE_LENGTH)
i := 0
for ; i < group_e.CREATE_GROUP_MAX_ATTEMPT; i++ {
success, err := res_m.CheckCode(model, code)
if err != nil || !success {
break
}
r, err := group_m.FindGroupByCode(model, code)
if err == nil && r == nil {
break
}
code = group_m.GenerateGroupCode(group_e.GROUP_DEFAULT_CODE_LENGTH)
}
if i >= group_e.CREATE_GROUP_MAX_ATTEMPT {
return myContext, myerr.NewSysError("Failed in generating groupId")
}
groupId := group_e.OverseaGroupNamePrefix + code
groupId, err = tencentyun.CreateGroup(name, groupId)
if err != nil {
return myContext, err
}
channelId := getUUID()
_, _, err = agora.CreateGroupAgora(channelId, uint32(userId))
if err != nil {
// 回滚,删除刚刚建立的TX群组
tencentyun.DestroyGroup(groupId, false)
return myContext, err
}
roomType := group_e.OverseaRoom
g := group_m.GroupInfo{
ImGroupId: groupId,
TxGroupId: groupId,
Type: uint16(roomType),
Code: code,
OriginCode: code,
Owner: userId,
Name: name,
Introduction: introduction,
Notification: notification,
FaceUrl: faceUrl,
Country: user.Country,
ChannelId: channelId,
MicOn: true,
LoadHistory: false,
MicNumType: group_e.TenMicNumType,
TouristMic: 1,
TouristSendMsg: 1,
TouristSendPic: 1,
}
if err := group_s.NewGroupService(myContext).CreateGroup(userId, &g); err != nil {
// 回滚,删除刚刚建立的TX群组
tencentyun.DestroyGroup(groupId, false)
return myContext, err
}
gm := group_m.GroupMember{
GroupId: groupId,
UserId: userId,
}
if err = gm.Create(model.Db); err != nil {
model.Log.Warnf("Failed to set GroupMember +%v", gm)
}
resp.ResponseOk(c, CreateGroupRsp{ImGroupId: groupId, Code: code})
return myContext, nil
}
func getUUID() string {
return strings.Replace(uuid.NewV4().String(), "-", "", -1)
}
// @Tags 群组
// @Summary 撤群
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200
// @Router /v1/imGroup/group/{groupId} [delete]
func DestroyGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
if !user_m.IsSuperUser(userId) {
return myContext, bizerr.NoPrivileges
}
// 参数已经是TxGroupId,不需要再转换了
err = tencentyun.DestroyGroup(groupId, false)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, groupId)
return myContext, nil
}
// @Tags 群组
// @Summary 查询群信息(运营用)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param code path string true "群CODE"
// @Success 200 {object} cv.GroupInfo
// @Router /v1/imGroup/group/{code} [get]
func GetGroupInfo(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
code := c.Param("code")
if len(code) <= 0 {
return myContext, myerr.NewSysError("code 为必填项")
}
model := domain.CreateModelContext(myContext)
r, err := group_m.FindGroupByCode(model, code)
if r == nil {
return myContext, bizerr.GroupNotFound
}
groupInfo, err := tencentyun.GetGroupInfo(model, []string{r.ImGroupId}, true)
if err != nil {
return myContext, err
}
if len(groupInfo) < 1 {
return myContext, myerr.NewSysError("ImGroupId does not exists.")
}
info := &groupInfo[0]
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
result := group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: r.TxGroupId,
Name: r.Name,
Introduction: r.Introduction,
Notification: r.Notification,
FaceUrl: r.FaceUrl,
Owner_Account: info.Owner_Account,
CreateTime: info.CreateTime,
LastMsgTime: info.LastMsgTime,
NextMsgSeq: info.NextMsgSeq,
MemberNum: info.MemberNum,
MaxMemberNum: info.MaxMemberNum,
ShutUpAllMember: info.ShutUpAllMember,
Code: r.Code,
CountryIcon: countryInfo[r.Country],
MicNumType: int(r.MicNumType),
},
}
for _, i := range info.MemberList {
result.MemberList = append(result.MemberList, group_cv.MemberListInfo{
Member_Account: i.Member_Account,
JoinTime: i.JoinTime,
LastSendMsgTime: i.LastSendMsgTime,
})
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 查询群详细信息
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} cv.GroupDetail
// @Router /v1/imGroup/detail/{groupId} [get]
func GetGroupDetail(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
groupId = groupInfo.ImGroupId
memberCount, err := group_m.GetMemberCount(model.Db, groupId)
if err != nil {
return myContext, err
}
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
themeUrl := ""
var themeId uint64 = 0
var themeType uint8 = 1
if groupInfo.ThemeId > 0 {
//官方主题
// 找不到的,默认为空(可能被后台删了)
themeType = 1
themes, _ := res_m.GroupThemeGetAll(model.Db)
for _, i := range themes {
if i.ID == uint64(groupInfo.ThemeId) {
themeUrl = i.Url
themeId = i.ID
break
}
}
} else {
//可能是自定义主题
themeId, themeUrl, err = group_m.GetShowCustomTheme(model, groupInfo.ImGroupId)
if err != nil {
return myContext, err
}
if themeId != 0 {
themeType = 2
}
}
result := group_cv.GroupDetail{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: groupInfo.TxGroupId,
Name: groupInfo.Name,
Introduction: groupInfo.Introduction,
Notification: groupInfo.Notification,
FaceUrl: groupInfo.FaceUrl,
MemberNum: memberCount,
Code: groupInfo.Code,
CountryIcon: countryInfo[groupInfo.Country],
MicNumType: int(groupInfo.MicNumType),
TouristMic: groupInfo.TouristMic,
TouristSendMsg: groupInfo.TouristSendMsg,
TouristSendPic: groupInfo.TouristSendPic,
MemberFee: groupInfo.MemberFee,
},
MicOn: groupInfo.MicOn,
LoadHistory: groupInfo.LoadHistory,
ThemeId: themeId,
ThemeUrl: themeUrl,
ThemeType: themeType,
Role: group_e.GROUP_VISITOR,
}
result.TotalConsume, err = gift_cv.GetGroupConsumeTotal(model, groupId)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupDetail, before GetGroupTop3Consume: +%v", result)
result.TopConsumers, err = billboard_cv.GetGroupTop3Consume(model, groupId, myUserId)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupDetail, after GetGroupTop3Consume: +%v", result)
result.WelcomeText, _, _, err = myService.GetWelcomeText(groupInfo)
if err != nil {
return myContext, err
}
result.WelcomeText = strings.ReplaceAll(result.WelcomeText, "@%s", "")
result.DiceNum = group_e.GROUP_DICE_NUM_DEFAULT
result.DiceType = 1
gs := group_m.GroupSetting{GroupId: groupId}
err = gs.Get(model.Db)
if err == nil {
result.DiceNum = gs.DiceNum
result.DiceType = gs.DiceType
} else if err != gorm.ErrRecordNotFound {
return myContext, err
}
roles, _, err := group_m.GetRolesInGroup(model, groupInfo.ImGroupId)
if err != nil {
return myContext, err
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
isGroupMember, err := group_m.IsGroupMember(model.Db, groupId, userId)
if err != nil {
return myContext, err
}
if isGroupMember {
result.Role = group_e.GROUP_MEMBER
}
groupUser := group_m.GroupUser{Model: model, UserId: userId}
msgStatus, err := groupUser.Get()
if err != nil {
return myContext, err
}
// 默认为免打扰
ok := false
if result.MsgStatus, ok = msgStatus[groupId]; !ok {
//result.MsgStatus = group_enum.DoNotDisturbMsgStatusGroupUser
result.MsgStatus = group_e.NormalMsgStatusGroupUser
}
emptyStr := ""
if len(groupInfo.Password) > 0 {
// 代表有密码
result.Password = &emptyStr
}
userIds := make([]uint64, 0)
for u, r := range roles {
userIds = append(userIds, u)
if u == userId {
if r == group_e.GROUP_OWNER || r == group_e.GROUP_MANAGER {
// 如果用户是OW或经理,可以看到密码,同时设置角色
result.Role = r
if len(groupInfo.Password) > 0 {
result.Password = &groupInfo.Password
}
} else if r == group_e.GROUP_ADMIN {
// 如果用户是管理员,仅设置角色
result.Role = r
}
}
}
userIds = append(userIds, groupInfo.Owner)
users, err := user_cv.GetUserTinyMap(userIds)
if err != nil {
return myContext, err
}
result.Owner, err = user_cv.GetUserDetail(model, groupInfo.Owner, userId)
if err != nil {
return myContext, err
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return myContext, myerr.WrapErr(err)
}
//extIds := make([]string, 0)
//for _, i := range users {
// extIds = append(extIds, i.ExternalId)
//}
/* fixme:为了性能,直接不查IM在线状态
status, err := tim_m.GetOnlineStatus(model, extIds)
if err != nil {
return myContext, err
}
*/
superManagerMap, err := cv.GetSuperManagerMap(userIds)
if err != nil {
return myContext, err
}
status := make(map[string]uint, 0)
for u, _ := range users {
m := users[u]
result.RoleMembers = append(result.RoleMembers, cv.RoleMemberInfo{
CvUserBase: cv.CvUserBase{
Avatar: &m.Avatar,
ExternalId: &m.ExternalId,
Nick: &m.Nick,
Sex: &m.Sex,
Country: &m.CountryIcon,
CountryIcon: &m.CountryIcon,
Code: &m.Code,
IsPrettyCode: m.IsPrettyCode,
IsVip: vips[m.Id] != nil,
IsOfficialStaff: superManagerMap[m.Id],
VipExpireTime: vips[m.Id],
},
Role: roles[u],
OnlineStatus: status[m.ExternalId],
})
}
sort.SliceStable(result.RoleMembers, func(i, j int) bool {
if result.RoleMembers[i].Role > result.RoleMembers[j].Role {
return true
} else if result.RoleMembers[i].Role == result.RoleMembers[j].Role {
if result.RoleMembers[i].OnlineStatus > result.RoleMembers[j].OnlineStatus {
return true
} else if result.RoleMembers[i].OnlineStatus == result.RoleMembers[j].OnlineStatus && *result.RoleMembers[i].Code > *result.RoleMembers[j].Code {
return true
}
}
return false
})
// 截取前N个
endPos := common.GROUP_ROLE_VIEW_LIMIT
if endPos > len(result.RoleMembers) {
endPos = len(result.RoleMembers)
}
result.RoleMembers = result.RoleMembers[0:endPos]
// todo: 直接用全量接口,只为方便
supportLevels, err := myService.GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
result.SupportLevel = supportLevels[groupId]
ResponseOk(c, result)
return myContext, nil
}
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
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-group/docs" _ "hilo-group/docs"
"hilo-group/route/group_r"
) )
func InitRouter() *gin.Engine { func InitRouter() *gin.Engine {
...@@ -15,6 +16,99 @@ func InitRouter() *gin.Engine { ...@@ -15,6 +16,99 @@ 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")
println(v1) imGroup := v1.Group("/imGroup")
{
imGroup.GET("/popular", wrapper(group_r.GetPopularGroups))
imGroup.GET("/latest", wrapper(group_r.GetLatestGroups))
imGroup.GET("/recommended", wrapper(group_r.GetRecommendGroup))
//
imGroup.POST("/group", wrapper(group_r.CreateGroup))
imGroup.DELETE("/group/:groupId", wrapper(group_r.DestroyGroup))
imGroup.GET("/group/:code", wrapper(group_r.GetGroupInfo))
imGroup.GET("/detail/:groupId", wrapper(GetGroupDetail))
//imGroup.PUT("/group/:groupId", wrapper(ModifyGroupInfo))
//imGroup.GET("/search/:code", wrapper(SearchGroup))
//imGroup.DELETE("/member/:groupId", wrapper(LeaveGroup))
//imGroup.PUT("/permanent/:groupId", wrapper(AddPermanentMember))
//imGroup.DELETE("/permanent/:groupId", wrapper(RemovePermanentMember))
//imGroup.GET("/permanent/:groupId", wrapper(GetPermanentMember))
//imGroup.GET("/myRecent", wrapper(GetRecentGroup))
//imGroup.GET("/myPermanent", wrapper(GetMyGroup))
//
//imGroup.GET("/visitors/:groupId", wrapper(GetGroupVisitors))
//imGroup.GET("/ownPublicGroup/:userExternalId", wrapper(GetOwnPublicGroup))
//// 2.19的新接口
//imGroup.GET("/ownGroup", wrapper(GetOwnGroup))
//imGroup.GET("/theirGroup/:userExternalId", wrapper(GetTheirGroups))
//imGroup.PUT("/pluginReady/:groupId", wrapper(PluginReady))
//imGroup.GET("/roomInfo/:groupId", LogRequestTime, wrapper(GetRoomInfo))
//
//imGroup.GET("/password/:groupId", wrapper(GetGroupPassword))
//imGroup.GET("/role/:groupId", wrapper(GetGroupRole))
//imGroup.PUT("/role/:groupId", wrapper(SetGroupRole))
//imGroup.POST("/role/accept", wrapper(AcceptMemberInvite))
//imGroup.GET("/admin/:groupId", wrapper(GetGroupAdmin))
//
//imGroup.PUT("/blacklist/:groupId", wrapper(AddGroupBlacklist))
//imGroup.DELETE("/blacklist/:groupId", wrapper(RemoveGroupBlacklist))
//imGroup.GET("/blacklist/:groupId", wrapper(GetGroupBlacklist))
//imGroup.PUT("/kick/:groupId", wrapper(KickGroupMembers))
//
//imGroup.PUT("/allGroupMsg", wrapper(SendTextMsg))
//
//imGroup.PUT("/welcomeText/:groupId", wrapper(SetWelcomeText))
//imGroup.GET("/support/page/:groupId", wrapper(GetSupportPage))
//imGroup.GET("/support/detail", wrapper(GetSupportDetail))
//imGroup.GET("/support/award/:groupId", wrapper(TryAddSupporter))
//imGroup.POST("/support/award/:groupId", wrapper(TakeSupportAward))
//
//// 操作类,普通用户不用
//imGroup.PUT("/memberLimit", wrapper(SetGroupMemberLimit))
//imGroup.PUT("/info/reset", wrapper(ResetGroupInfo), OperationLog)
//imGroup.PUT("/upgrade", wrapper(UpgradeGroup))
//imGroup.PUT("/downgrade", wrapper(DowngradeGroup))
//
//imGroup.GET("/mic/all", wrapper(GroupMicAllInfoFive))
//imGroup.GET("/mic/all/type", wrapper(GroupMicAllInfoTen))
//imGroup.GET("/mic/all/type/new", wrapper(GroupMicAllInfoType))
//imGroup.PUT("/mic/num", wrapper(GroupMicNumChange))
//imGroup.GET("/mic/num", wrapper(GroupMicNum))
//imGroup.POST("/mic/emoji/msg", wrapper(GroupSendMicSystemMsg))
//imGroup.POST("/mic/in/invite/dialog", wrapper(GroupMicInInviteDialog))
//imGroup.POST("/mic/task/invite/dialog", wrapper(GroupMicTaskInviteDialog))
//imGroup.POST("/mic/in", LogRequestTime, wrapper(GroupMicIn))
//imGroup.POST("/mic/invite", LogRequestTime, wrapper(GroupMicInvite))
//imGroup.POST("/mic/leave", LogRequestTime, wrapper(GroupMicLeave))
//imGroup.POST("/mic/lock", wrapper(GroupMicLock))
//imGroup.POST("/mic/unlock", wrapper(GroupMicUnLock))
//imGroup.POST("/mic/speech/open", wrapper(GroupMicSpeechOpen))
//imGroup.POST("/mic/speech/close", wrapper(GroupMicSpeechClose))
//imGroup.POST("/mic/mute", wrapper(GroupMicMute))
//imGroup.POST("/mic/unmute", wrapper(GroupMicUnmute))
//imGroup.PUT("/in", LogRequestTime, wrapper(GroupIn))
//imGroup.POST("/leave", wrapper(GroupLeave))
//imGroup.POST("/kick", wrapper(GroupKick))
//imGroup.PUT("/user/msg/status", wrapper(GroupUserMsg))
//imGroup.POST("/report", wrapper(GroupReport))
//imGroup.GET("/banner/list", wrapper(GroupBannerList))
//imGroup.GET("/roomBanners", wrapper(RoomBannerList))
//imGroup.PUT("/roomBanners", wrapper(NotifyRoomBannerListChange))
//imGroup.POST("/mic/gift", wrapper(GroupMicGift))
//imGroup.POST("/mic/mass", wrapper(GroupMicMass))
//imGroup.POST("/mgr/mass", wrapper(GroupMgrMass))
//imGroup.POST("/mgr/clearScreen", wrapper(GroupMgrClearScreen))
//imGroup.GET("/online/users", wrapper(GroupInUsers))
//imGroup.GET("/online/users/new", wrapper(GroupInUserNew))
//imGroup.GET("/country", wrapper(GetGroupByCountry))
//imGroup.GET("/country/prior", wrapper(GroupountryPrior))
//
//imGroup.POST("/theme/custom", wrapper(GroupThemeAdd))
//imGroup.GET("/theme/custom/config", wrapper(GroupThemeConfig))
//imGroup.PUT("/theme/custom/using", wrapper(GroupThemeUsing))
//imGroup.GET("/theme/custom/all", wrapper(GroupThemeValidAll))
//
//imGroup.GET("/medal/all", wrapper(GroupMedalAll))
//imGroup.GET("/medal/room", wrapper(GetRoomMedal))
}
return r return r
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment