Commit b4d52c16 authored by hujiebin's avatar hujiebin

Merge branch 'feature/jackpot' into 'master'

Feature/jackpot

See merge request !1
parents 5a78e911 1c33ff36
swag:
swag init
\ No newline at end of file
proto:
protoc --go_out=./ --go-grpc_out=. ./protocol/*.proto
\ No newline at end of file
package diamond_e
import "hilo-user/resource/mysql"
type StatusAccount = mysql.Type
const (
Normal StatusAccount = 1
//冻结,只是限制减少,不限制增加
Frozen StatusAccount = 2
)
type OperateType = mysql.Type
const (
//注册
/* REGISTER OperateType = 1
//建立融云会话
SessionPay OperateType = 2
//购买钻石
BuyDiamond OperateType = 3
//发送礼物
SendGift OperateType = 4
//接受礼物
ReceiveGift OperateType = 5
//匹配条件
MatchCondition OperateType = 6*/
SendGift OperateType = 1 //发送礼物
MatchCondition OperateType = 2 //匹配条件
SessionPay OperateType = 3 //建立融云会话
BuyDiamond OperateType = 4 //购买钻石
ReceiveGift OperateType = 5 //接受礼物
REGISTER OperateType = 6 //注册
MgrSend OperateType = 8 //平台赠送
VideoCost OperateType = 9 //1对1视频花费
MgrReduce OperateType = 10 //平台扣除
ActivityBillboard OperateType = 11 //活动榜单奖励
ExchangeBean OperateType = 12 //钻石兑换豆子
ActivityGroupBillboard OperateType = 13 //活动榜单奖励
DailyInAppVip OperateType = 14 //每日登陆领取钻石(VIP)
GroupIMMass OperateType = 15 //群中IM群发
DailyInAppCommon OperateType = 16 //每日登陆领取钻石(普通用户)
GroupSupportAdmin OperateType = 17 //群组支持(利益分配者)
GroupSupportMgr OperateType = 18 //群主支持(助手)
MgrBillDiamond OperateType = 19 //管理人单据送钻石
Headwear OperateType = 20 //送头饰扣费
Property OperateType = 21 //送坐骑扣费
LuckyWheelJoin OperateType = 22 //参与转盘扣费
LuckyWheelCancel OperateType = 23 //转盘取消
LuckyWheelWin OperateType = 24 //转盘奖励
LuckWheelGroupOwer OperateType = 25 //转盘群主抽成
DealerTransfer OperateType = 26 //币商转账
GroupCustomTheme OperateType = 27 //购买群组自定义主题
RocketAward OperateType = 28 //火箭奖励
LuckyboxBuy OperateType = 29 //幸运盒子购买
LuckyboxAward OperateType = 30 //幸运盒子奖励
PrivateGift OperateType = 31 // 私聊送礼物
PrivateGiftReturn OperateType = 32 // 私聊送礼物退款
ActivityTriggerAward OperateType = 33 //活动触发奖励
VideoTradeUnionGift OperateType = 34 // 视频送礼物
VideoTradeUnionGiftReturn OperateType = 35 // 视频送礼物退款
GlobalBroadcast OperateType = 36 //全球发布消息
TaskAward OperateType = 37 //任务奖励
FruitMachineAward OperateType = 38 // 水果机奖励
FruitMachineBet OperateType = 39 // 水果机投注
Noble OperateType = 40 //购买/赠送贵族
FruitTycoonAward OperateType = 41 // 水果大亨奖励
Checkout OperateType = 42 //checkout购买
LuckyboxCycle OperateType = 43 //幸运盒子回收奖励
ActivityRechargeFirst OperateType = 44 //首次充值奖励
NewUserInvite OperateType = 45 // 新用户奖励活动
GeneralActivity OperateType = 46 // 一般性活动奖励
PowerSupportOwner OperateType = 47 // 势力支持(势力主)
PowerSupportAssistant OperateType = 48 // 势力支持(助手)
VideoMinute OperateType = 49 //1对1视频(分钟扣费)
MatchMinute OperateType = 50 //匹配视频(第一分钟扣费)
VideoMinuteBack OperateType = 51 //1对1视频(分钟扣费,返回)
VideoMinuteTotal OperateType = 52 //1对1视频(分钟扣费,返回)
GroupActivity OperateType = 53 //创建群组活动
GroupActivityReward OperateType = 54 //群组活动奖励
PayerMax OperateType = 55 //payerMax/茄子支付购买
BuyPinkDiamond OperateType = 56 //购买粉钻
VideoCostPink OperateType = 57 //1对1视频送礼(粉钻)
MatchMinutePink OperateType = 58 //匹配视频(第一分钟扣费)(粉钻)
VideoMinuteTotalPink OperateType = 59 //1对1视频(分钟扣费,返回)(粉钻)
SendPinkGift OperateType = 60 //送粉钻礼物 ---占位---暂不开放 数据库配置表中暂未配置
MatchMinuteGiftPink OperateType = 61 //匹配视频送礼(粉钻)
MatchMinuteGiftPinkTime OperateType = 62 //匹配视频加时送礼(粉钻)
JoinGroupCost OperateType = 63 //加入群组扣费
JoinGroupAdd OperateType = 64 //加入群组,群主得黄钻
GameJoin OperateType = 65 //加入游戏扣费
GameAward OperateType = 66 //游戏结算奖励
GameRefund OperateType = 67 //游戏退费
)
const (
DiamondYellow mysql.Type = 1
DiamondPink mysql.Type = 2
)
package user_e
type ReportType string
type GameType int
type GameOpt int
type GameStatus uint8
type GamerStatus uint8
type GamerPlayerStatus uint8
type GameMode = int
const (
ReportTypeGameStart ReportType = "user_start" // 战斗开始通知
ReportTypeGameSettle ReportType = "user_settle" // 战斗结算通知
GameAutoMatchYes = 1 // 游戏自动匹配
GameAutoMatchNo = 0 // 游戏非自动匹配
GameTypeLudo GameType = 1 // ludo
GameTypeUno GameType = 2 // uno
GameModeQuick GameMode = 0
GameModeClassic GameMode = 1
GameOptCreate GameOpt = 0 // 创建游戏
GameOptJoin GameOpt = 1 // 加入游戏,自动准备
GameOptExit GameOpt = 2 // 退出游戏
GameOptClose GameOpt = 3 // 创建者关闭游戏
//GameOptReady GameOpt = 2 // 准备游戏
//GameOptCancelReady GameOpt = 3 // 取消准备游戏
GameStatusNoStart GameStatus = 0 // 未开始
GameStatusGaming GameStatus = 1 // 游戏中
GameStatusEnd GameStatus = 2 // 游戏结束
GamerStatusUnready GamerStatus = 0 // 未开始
GamerStatusGaming GamerStatus = 1 // 游戏中
GamerStatusEnd GamerStatus = 2 // 游戏结束
GamerExit GamerStatus = 3 // 自己退出游戏
GamerClose GamerStatus = 4 // 创建者关闭游戏
//GamerStatusReady GamerStatus = 1 // 准备
//GamerExit GamerStatus = 4 // 自己退出游戏
MgIdLudo = "1468180338417074177"
MgIdUno = "1472142559912517633"
)
package groupPower_e
import "hilo-user/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 "hilo-user/resource/mysql"
// 信令消息(不显示公屏工,不记入消息历史,不影响未读数)
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 //房间-用户群组身份变化
GroupGameInfoLudo TypeSignalMsg = 200 // 房间-游戏信息-ludo
GroupGameSettleLudo TypeSignalMsg = 201 // 房间-游戏结算信息-ludo
GroupGameInfoUno TypeSignalMsg = 202 // 房间-游戏信息-uno
GroupGameSettleUno TypeSignalMsg = 203 // 房间-游戏结算信息-uno
)
// 群组麦位数量类型
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
//
)
// 公屏消息
type TypePublicScreenMsg = mysql.Type
const (
UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组
UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间
UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户
RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色
RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色
ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用
RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果
GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物
GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5
JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息
RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息
LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖
FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖
EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间
GameLudoPubMsg TypePublicScreenMsg = 101 // Ludo游戏公屏
GameUnoPubMsg TypePublicScreenMsg = 102 // uno游戏公屏
)
package headwear_e
import "git.hilo.cn/hilo-common/resource/mysql"
type UserHeadwearUsing = mysql.Type
const (
YesUsing UserHeadwearUsing = 1
NoUsing UserHeadwearUsing = 0
)
type UserHeadwearLogOrginType = mysql.Type
const (
Mgr UserHeadwearLogOrginType = 1
//购买,或者别人购买
Send UserHeadwearLogOrginType = 2
Activity UserHeadwearLogOrginType = 3
Rocket UserHeadwearLogOrginType = 4
//活动阀值自动触发奖励
ActivityTrigger UserHeadwearLogOrginType = 5
//首次充值奖励
ActivityRechargeFirst UserHeadwearLogOrginType = 6
//别人赠送
Give UserHeadwearLogOrginType = 7
GeneralActivity UserHeadwearLogOrginType = 8
)
type UserHeadwearLogType mysql.Type
const (
AddSecond UserHeadwearLogType = 1
UpdateEndTime UserHeadwearLogType = 2
Del UserHeadwearLogType = 3
)
package match_e
import "hilo-user/resource/mysql"
/****************************/
type MatchDetailDataChange mysql.NumAll
const (
AddDataChange MatchDetailDataChange = 1
ReduceDataChange MatchDetailDataChange = 2
ZeroDataChange MatchDetailDataChange = 0
)
/******元素分数***************/
/*type EnumCountType mysql.Type
const (
PriorityEnumCountType EnumCountType = 1
ExcellentEnumCountType EnumCountType = 2
RelationEnumCountType EnumCountType = 3
)*/
/*const (
//接收到礼物的数量
ReceiveGiftNumCountType EnumCountType = 1
//接收到礼物的频率
ReceiveGiftFCountType EnumCountType = 2
//被举报
BeReportCountType EnumCountType = 3
//被拉黑
BeBlackCountType EnumCountType = 4
//支付次数
PayCountType EnumCountType = 5
//被喜欢的次数
LikeMeType EnumCountType = 6
//新用户
NewUserType EnumCountType = 7
//连续被拒
AgainRefuse EnumCountType = 8
//每天新登陆用户
DailyUserType EnumCountType = 9
//活跃等级
ActiveGrade EnumCountType = 10
//连续同性
AgainSameSex EnumCountType = 11
//匹配推送次数
MatchSuccessNum EnumCountType = 12
//匹配推送接受次数
MatchConfirmNum EnumCountType = 13
//接通率
MatchConfirmRate EnumCountType = 14
//免费加时
MatchFreeTimeNum EnumCountType = 15
//礼物加时
MatchGiftTimeNum EnumCountType = 16
//加时率
MatchAddTimeRate EnumCountType = 17
//工会成员
TradeUnion EnumCountType = 18
//匹配拒绝
RelationMatchRefuse EnumCountType = 19
//匹配用户
RelationMatchUser EnumCountType = 20
)*/
// 优先度排序
type PriorityUserFormOriginType mysql.Type
const (
//钻石余额
PriorityDiamond PriorityUserFormOriginType = 1
//首充
PriorityFirstCharge PriorityUserFormOriginType = 2
//财富等级
PriorityWealthGrade PriorityUserFormOriginType = 3
//被举报
PriorityBeReport PriorityUserFormOriginType = 4
//被拉黑
PriorityBeBlack PriorityUserFormOriginType = 5
//近期充值
PriorityRecentlyPay PriorityUserFormOriginType = 6
//新用户
PriorityNewUserType PriorityUserFormOriginType = 7
//连续被拒
PriorityAgainRefuse PriorityUserFormOriginType = 8
//每天新登陆用户
PriorityDailyUserType PriorityUserFormOriginType = 9
//活跃等级
PriorityActiveGrade PriorityUserFormOriginType = 10
//工会
PriorityTradeUnion PriorityUserFormOriginType = 11
//多次匹配到同性
PriorityAgainSameSex PriorityUserFormOriginType = 12
)
var PriorityMap = map[PriorityUserFormOriginType]string{
PriorityDiamond: "钻石余额",
PriorityFirstCharge: "首充",
PriorityWealthGrade: "财富等级",
PriorityBeReport: "被举报",
PriorityBeBlack: "被拉黑",
PriorityRecentlyPay: "近期充值",
PriorityNewUserType: "新用户",
PriorityAgainRefuse: "连续被拒",
PriorityDailyUserType: "每天新登陆用户",
PriorityActiveGrade: "活跃等级",
PriorityTradeUnion: "工会",
PriorityAgainSameSex: "连续同性",
}
// 质量排序
type ExcellentUserFormOriginType mysql.Type
const (
//被喜欢的次数
ExcellentLikeMe ExcellentUserFormOriginType = 1
//接收礼物数量
ExcellentReceiveGiftNumChange ExcellentUserFormOriginType = 2
//接收礼物次数
ExcellentReceiveGiftFChange ExcellentUserFormOriginType = 3
//被投诉次数
ExcellentBeReport ExcellentUserFormOriginType = 4
//被拉黑的次数
ExcellentBeBlack ExcellentUserFormOriginType = 5
//魅力等级
ExcellentCharmGrade ExcellentUserFormOriginType = 6
//被付费建立融云会话
ExcellentSessionCreate ExcellentUserFormOriginType = 7
//接通率
ExcellentMatchConfirmRate ExcellentUserFormOriginType = 8
//加时率(视频通话加时次数(免费加时成功 + 礼物加时成功)/视频通话次数(匹配成功的次数))
ExcellentAddTimeRate ExcellentUserFormOriginType = 9
//工会成员
ExcellentTradeUnion ExcellentUserFormOriginType = 10
//匹配成功次数
ExcellentMatchSuccessNum ExcellentUserFormOriginType = 11
//匹配确认次数
ExcellentMatchConfirmNum ExcellentUserFormOriginType = 12
//匹配免费加时的次数
ExcellentMatchFreeTimeNum ExcellentUserFormOriginType = 13
//匹配礼物加时次数
ExcellentMatchGiftTimeNum ExcellentUserFormOriginType = 14
)
var ExcellentMap = map[ExcellentUserFormOriginType]string{
ExcellentLikeMe: "喜欢我",
ExcellentReceiveGiftNumChange: "接收礼物数量",
ExcellentReceiveGiftFChange: "接收礼物次数",
ExcellentBeReport: "被投诉次数",
ExcellentBeBlack: "被拉黑次数",
ExcellentCharmGrade: "魅力等级",
ExcellentSessionCreate: "被付费建立融云会话",
ExcellentMatchConfirmRate: "接通率",
ExcellentAddTimeRate: "加时率",
ExcellentTradeUnion: "工会成员",
ExcellentMatchSuccessNum: "匹配成功次数",
ExcellentMatchConfirmNum: "匹配确认次数",
ExcellentMatchFreeTimeNum: "匹配免费加时次数",
ExcellentMatchGiftTimeNum: "匹配礼物加时次数",
}
// 关系排序
type RelationUserFormOriginType mysql.Type
const (
//喜欢的用户
RelationUserLike RelationUserFormOriginType = 1
//匹配拒绝用户
RelationMatchRefuse RelationUserFormOriginType = 2
//匹配过的用户
RelationMatchUser RelationUserFormOriginType = 3
//付费发送过消息但没进行过视频聊天
RelationSessionNoMatchConfirm RelationUserFormOriginType = 4
//上一次匹配的用户
RelationMatchUserLastTime RelationUserFormOriginType = 5
)
var RelationMap = map[RelationUserFormOriginType]string{
RelationUserLike: "喜欢的用户",
RelationMatchRefuse: "匹配被拒绝",
RelationMatchUser: "匹配上的用户",
RelationSessionNoMatchConfirm: "付费发送过消息但没进行过视频聊天",
RelationMatchUserLastTime: "上一次匹配的用户",
}
/******匹配确认***********************************/
type MatchConfirmStatus mysql.Type
const (
Success MatchConfirmStatus = 1
Fail MatchConfirmStatus = 2
Temp MatchConfirmStatus = 3
)
type MatchConfirmUserAcceptRefuse mysql.Type
const (
AcceptMatchConfirmUser MatchConfirmUserAcceptRefuse = 1
RefuseMatchConfirmUser MatchConfirmUserAcceptRefuse = 2
)
type MatchCharmUserScoreDetailType = mysql.Type
const (
GiftReceiveCharmType MatchCharmUserScoreDetailType = 1
GiftReceiveVipCharmType MatchCharmUserScoreDetailType = 2
)
type MatchWealthUserScoreDetailType = mysql.Type
const (
GiftReceiveWealthType MatchWealthUserScoreDetailType = 1
GiftReceiveVipWealthType MatchWealthUserScoreDetailType = 2
)
package msg_e
import "git.hilo.cn/hilo-common/resource/mysql"
//消息发送类型,消息接收者是谁 1:通知 2:官网 3:被喜欢通知 (注意:MsgReceiveType 同 MsgUserRecordType 不是树形关系s)
//MsgReceive 结构体服务
type MsgReceiveType = mysql.Type
const (
//小助手的通知
UserMsgReceiveType MsgReceiveType = 1
//系统的通知
SysMsgReceiveType MsgReceiveType = 2
//喜欢消息
LikeMeReceiveType MsgReceiveType = 3
//工会用户通知
TradeUnionReceiveType MsgReceiveType = 4
//用户召回
UserRecall MsgReceiveType = 5
//video请求
VideoSend MsgReceiveType = 6
//访问
VisitReceiveType MsgReceiveType = 7
//拉黑
BlockReceiveType MsgReceiveType = 8
//短信验证码
SmsCode MsgReceiveType = 9
)
//跳转类型 0:无调整 1:网页跳转 2:app跳转 3:跳转到钻石 4:跳转到背包
type ActionType = uint16
const (
NonActionType ActionType = 0
WebActionType ActionType = 1
AppActionType ActionType = 2
)
//消息记录类型(设计的不好,应该是根据消息样式类型设计,而不是业务类型,渣渣)
type MsgUserRecordType = mysql.Type
const (
//新用户
//NewUserType MsgUserRecordType = 1
//举报
ReportType MsgUserRecordType = 2
//喜欢我
//LikeMeType MsgUserRecordType = 3
//重置图片
ResetAvatarType MsgUserRecordType = 4
//
//喜欢我
LikeMeType MsgUserRecordType = 5
//访问
VisitType MsgUserRecordType = 6
//新匹配记录
MatchHistoryType MsgUserRecordType = 7
//互相喜欢
LikeEachType MsgUserRecordType = 8
//你获得s%钻石的礼物收益!
DiamondIncome MsgUserRecordType = 9
//榜单结果
ActivityBillboardResult MsgUserRecordType = 10
//榜单钻石收益
ActivityBillboardDiamond MsgUserRecordType = 11
//榜单坐骑收益
ActivityBillboardProperty MsgUserRecordType = 12
//通过收礼物获得豆子
ActivityBeanProperty MsgUserRecordType = 13
//管理人送钻石
MgrSendDiamondProperty MsgUserRecordType = 14
//群组榜单钻石收益
ActivityGroupBillboardDiamond MsgUserRecordType = 15
//群组榜单坐骑收益
ActivityGroupBillboardProperty MsgUserRecordType = 16
//群组支持收益
GroupSupport MsgUserRecordType = 17
//群组支持提醒结果
GroupSupportResult MsgUserRecordType = 18
//管理人送座驾
MgrSendProperty MsgUserRecordType = 19
//送道具(座驾,头饰都属于道具)
AddProps MsgUserRecordType = 20
//MISS活动获胜
ActivityBillboardBeLikeResult = 21
//CP活动获胜
ActivityBillboardCpResult = 22
//加入势力主
GroupPowerUserJoin = 23
//离开势力主
GroupPowerUserLeave = 24
//贵族
AddNoble = 25
//日充值活动通知
ActivityTriggerDayPay = 26
//也门活动通知
ActivityTriggerYemen = 27
//月充值活动通知
ActivityTriggerMonthPay = 28
FruitTycoonAward = 29 // 水果大亨获奖
LuckyboxRecycle = 30 //幸运盒子回收
HlTemp1 = 31 //产品黄蕾,2022/06/29 临时要求发给某人的小助手消息
HLTemp2 = 32 //问卷调查
NewUserInviteAuditPassed = 33 // 新用户奖励活动审核通过
NewUserInviteAuditFailed = 34 // 新用户奖励活动审核不通过
NewUserInviterAward = 35 // 新用户奖励活动邀请成功数达标
PowerSupportSalary = 36 // 势力扶持工资领取 提醒
CountryStarOrdinaryAward = 37 // 国家之星瓜分奖提醒
GroupActivityRewardMsg = 38 // 群组活动钻石奖励提醒
TemplateActAwardMsg = 39 // 通用模板活动奖励提醒
TemplateSmsCode = 40 // 通用模板活动奖励提醒
)
type MsgSysUserType = mysql.Type
const (
//系统消息
SysType MsgSysUserType = 1
//小助手消息
AssistantType MsgSysUserType = 2
)
//resMsgTransalte 中 msg_type 同 type, msg_type是属于一级类型 type属于二级类型。 msg_type 对应MsgReceiveType type:部分对应MsgUserRecordType MsgUserRecordType(应该是小助手的类型)
type MsgSysRecordType = mysql.Type
const (
//这个值木有意义,
SysMsgSysRecordType1 MsgSysRecordType = 1
SysMsgSysRecordType2 MsgSysRecordType = 2
)
package msg_e
// 公屏消息
type TypePublicScreenMsg uint8
const (
UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组
UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间
UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户
RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色
RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色
ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用
RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果
GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物
GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5
JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息
RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息
LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖
FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖
EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间
)
package property_e
import "git.hilo.cn/hilo-common/resource/mysql"
type UserPropertyUsing = mysql.Type
const (
YesUsing UserPropertyUsing = 1
NoUsing UserPropertyUsing = 0
)
type UserPropertyLogOrginType = mysql.Type
const (
//活动奖励
ActivityBillboardReward UserPropertyLogOrginType = 1
//
Operational UserPropertyLogOrginType = 2
//群组活动
ActivityGroupBillboardReward UserPropertyLogOrginType = 3
//赠送
Send UserPropertyLogOrginType = 4
//火箭游戏
Rocket UserPropertyLogOrginType = 5
//活动阀值触发奖励
ActivityBillboardTrigger UserPropertyLogOrginType = 6
//首次充值奖励
ActivityRechargeFirst UserPropertyLogOrginType = 7
Give UserPropertyLogOrginType = 8
GeneralActivity UserPropertyLogOrginType = 9 // 一般性活动
)
type UserPropertyLogType mysql.Type
const (
AddSecond UserPropertyLogType = 1
UpdateEndTime UserPropertyLogType = 2
Del UserPropertyLogType = 3
)
type PropertyType = uint16
const (
TypeNoble PropertyType = 1
TypeMedal PropertyType = 2
TypeHeaddress PropertyType = 3
TypeRide PropertyType = 4
)
package res_e
import "hilo-user/resource/mysql"
import "git.hilo.cn/hilo-common/resource/mysql"
type MsgIdType = uint
const (
DEFAULT_LANG = "en"
MSG_ID_GAME_CREATE MsgIdType = 1001
MSG_ID_GAME_JOIN MsgIdType = 1002
)
type ResMedalType = mysql.Type
......@@ -55,3 +52,9 @@ const (
type ResNameplateType = mysql.Type
type ResNameplateObtainType = mysql.Type
type ResNameplateScope = mysql.Type
type ResUserBag = mysql.Type
const (
ResUserBagGift ResUserBag = 1 // 背包道具-礼物
)
package user_e
import "hilo-user/resource/mysql"
import "git.hilo.cn/hilo-common/resource/mysql"
type ThirdPartyType = mysql.Type
......
package _const
const (
TRACEID = "traceId"
USERID = "userId"
EXTERNAL_ID = "externalId"
CODE = "code"
NICK = "nick"
AVATAR = "avatar"
COUNTRY = "country"
EXTERNALID1 = "externalId1"
EXTERNALID2 = "externalId2"
MGRID = "mgrId"
DEVICETYPE = "deviceType"
DEVICEVERSION = "deviceVersion"
APP_VERSION = "appVersion"
ACTION_RESULt = "actionResult"
URL = "url"
METHOD = "method"
IMEI = "imei"
LANGUAGE = "language"
)
package user_k
import (
"fmt"
)
const (
GameAdd = "user:add:%s"
GameLock = "user:lock:%s"
)
func GetGameAddKey(txGroupId string) string {
return fmt.Sprintf(GameAdd, txGroupId)
}
package robot_k
import "fmt"
const (
RobotGroupCd = "robot:group:cd:%s"
)
// 机器人上群cd
func GetRobotGroupCdKey(txGroupId string) string {
return fmt.Sprintf(RobotGroupCd, txGroupId)
}
......@@ -2,8 +2,8 @@ package user_k
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/redis_key"
"hilo-user/resource/mysql"
)
const (
......
package _const
import (
"encoding/json"
"fmt"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"net"
"runtime/debug"
"strings"
"time"
)
const DEFAULT_LANG = "en"
const DATETIME_FORMAT = "2006-01-02 15:04:05"
const DATE_FORMAT = "2006-01-02"
const DefaultAvatarMan = "hilo/manager/ea48b62d54a24a709de3c38702c89995.png"
func GetZeroTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
// 取最近的一个星期n
func GetLastDayOfWeek(t time.Time, n time.Weekday) time.Time {
weekDay := t.Weekday()
// 校正日期
if weekDay < n {
weekDay = 7 - n + weekDay
} else {
weekDay = weekDay - n
}
return t.AddDate(0, 0, -(int(weekDay)))
}
// 补全url,区分处理oss和aws两种情况
func MakeFullUrl(url string) string {
if strings.HasPrefix(url, config.GetConfigOss().OSS_CDN) || strings.HasPrefix(url, config.GetConfigAws().AWS_CDN) {
return url
} else if strings.HasPrefix(url, "nextvideo/") {
return config.GetConfigOss().OSS_CDN + url
} else if strings.HasPrefix(url, config.GetConfigAws().AWS_DIR) {
return config.GetConfigAws().AWS_CDN + url
} else {
return url
}
}
// 去除slice中的重复元素
func UniqueSliceUInt64(sliceIn []uint64) []uint64 {
sliceOut := make([]uint64, 0, len(sliceIn))
m := make(map[uint64]struct{}, len(sliceIn))
for _, i := range sliceIn {
if _, ok := m[i]; !ok {
m[i] = struct{}{}
sliceOut = append(sliceOut, i)
}
}
return sliceOut
}
func ToString(s interface{}) (string, error) {
b, err := json.Marshal(s)
if err != nil {
return "", nil
}
return string(b), nil
}
func SliceToMapUInt64(s []uint64) map[uint64]struct{} {
m := make(map[uint64]struct{}, len(s))
for _, i := range s {
m[i] = struct{}{}
}
return m
}
func GetClientIp() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", err
}
for _, address := range addrs {
// 检查ip地址判断是否回环地址
if ipNet, ok := address.(*net.IPNet); ok && ipNet.IP.IsGlobalUnicast() {
//if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
return ipNet.IP.String(), nil
}
}
}
return "", fmt.Errorf("can not find the client ip address")
}
func CheckGoPanic() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}
package user_cv
import (
"git.hilo.cn/hilo-common/resource/mysql"
)
type UserBag struct {
BagId mysql.ID `json:"bagId"` // 背包id
ResType mysql.Type `json:"resType"` // 道具类型 1:礼物道具
ResId mysql.ID `json:"resId"` // 道具资源id
GiftId mysql.ID `json:"giftId"` // 道具的礼物id
Name string `json:"name"` // 资源名称
DiamondNum mysql.Num `json:"diamondNum"` // 钻石数量
IconUrl string `json:"iconUrl"` // icon url
SvgaUrl string `json:"svgaUrl"` // svga url
Count mysql.Num `json:"count"` // 拥有数量
RemainDays int `json:"remainDays"` // 有效天数
}
package user_cv
import "git.hilo.cn/hilo-common/resource/mysql"
type MGetUserLevelData map[mysql.ID]CvUserLevel
type CvUserLevel struct {
UserId mysql.ID `json:"userId"` // 用户id
WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级
CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级
}
......@@ -2,7 +2,7 @@ package cache
import (
"encoding/json"
"hilo-user/domain"
"git.hilo.cn/hilo-common/domain"
"math/rand"
"time"
)
......
package user_c
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
redisV8 "github.com/go-redis/redis/v8"
"github.com/jinzhu/copier"
"hilo-user/_const/redis_key/user_k"
"hilo-user/domain"
"hilo-user/domain/cache"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
)
// 获取用户简要信息
......
package domain
import (
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-user/mycontext"
)
type CtxAndDb struct {
Db *gorm.DB
*mycontext.MyContext
Redis *redis.Client
}
package domain
//异步执行的接口
type AsyncEvent interface {
AsyncDo(model *Model, eventData interface{}, n int) error
AsyncSize() int
AsyncNoTxDo(model *Model, eventData interface{}, n int) error
AsyncNoTxSize() int
}
package event
import "hilo-user/domain"
import "git.hilo.cn/hilo-common/domain"
// 程序内部事件
type Base struct {
......
package user_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/resource/mysql"
)
//注册监听
var userEditEvent = new(event.Base)
/**
注册事件
*/
type GameEditEvent struct {
GameId mysql.ID `json:"userId"` // 游戏id
TxGroupId mysql.Str `json:"txGroupId"` // 群组id
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGameEditEventSync(callback func(model *domain.Model, event interface{}) error) {
userEditEvent.SyncList = append(userEditEvent.SyncList, callback)
}
//加入到异步操作中
func AddGameEditEventAsync(callback func(model *domain.Model, event interface{}) error) {
userEditEvent.AsyncList = append(userEditEvent.AsyncList, callback)
}
//领域事件发布
func PublishGameEditEvent(model *domain.Model, event interface{}) error {
//执行同步的领域事件
for _, callback := range userEditEvent.SyncList {
if err := callback(model, event); err != nil {
return err
}
}
// 执行异步的领域事件
if len(userEditEvent.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range userEditEvent.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("userEditEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package user_ev
import (
"hilo-user/_const"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/resource/mysql"
)
//注册监听
var reportGameInfoEvent = new(event.Base)
/**
注册事件
*/
type ReportGameInfoEvent struct {
UserId mysql.ID `json:"uid"` // 用户id,请求get_user_info 接口返回uid参数
ReportType user_e.ReportType `json:"report_type"` // 上报类型 user_start|user_settle
GameStartObject *GameStartObject `json:"user_start_object"` // user_start对应结构体
GameSettleObject *GameSettleObject `json:"user_settle_object"` // user_settle对应结构体
}
type GameStartObject struct {
MgId uint64 `json:"mg_id"` // 游戏id
MgIdStr string `json:"mg_id_str"` // 小游戏id数值型兼容字段(nodejs服务请使用当前字段)
RoomId string `json:"room_id"` // 接入方房间id
GameMode int32 `json:"user_mode"` // 游戏模式,设定游戏的一些功能(参与游戏的人数,出手时间,特定的玩法)
GameRoundId string `json:"user_round_id"` // 本局游戏的id (重复上报,使用该字段去重)
BattleStartAt int32 `json:"battle_start_at"` // 战斗开始时间(秒)
Players []PlayerObject `json:"players"` // player_object 数组
ReportGameInfoExtras string `json:"report_user_info_extras"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过1024字节,超过则截断
ReportGameInfoKey string `json:"report_user_info_key"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过64字节,超过则截断。接入方服务端可以根据这个字段来查询一局游戏的数据
}
type PlayerObject struct {
Uid string `json:"uid"` // 接入方uid,机器人为空字符
IsAi int32 `json:"is_ai"` // 0:普通用户,1:机器人
}
type GameSettleObject struct {
MgId uint64 `json:"mg_id"` // 游戏id
MgIdStr string `json:"mg_id_str"` // 小游戏id数值型兼容字段(nodejs服务请使用当前字段)
RoomId string `json:"room_id"` // 接入方房间id
GameMode int32 `json:"user_mode"` // 游戏模式
GameRoundId string `json:"user_round_id"` // 本局游戏的id (重复上报,使用该字段去重)
BattleStartAt uint32 `json:"battle_start_at"` // 战斗开始时间(秒)
BattleEndAt uint32 `json:"battle_end_at"` // 战斗结束时间(秒)
BattleDuration int32 `json:"battle_duration"` // 战斗总时间(秒)
Results []PlayerResultObject `json:"results"` // player_result_object 数组
ReportGameInfoExtras string `json:"report_user_info_extras"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过1024字节,超过则截断
ReportGameInfoKey string `json:"report_user_info_key"` // 游戏上报信息扩展参数(透传),取值范围:长度不超过64字节,超过则截断。接入方服务端可以根据这个字段来查询一局游戏的数据
}
type PlayerResultObject struct {
Uid string `json:"uid"` // 接入方uid,机器人为空字符
Rank int32 `json:"rank"` // 排名从1开始,平局排名相同
IsEscaped int32 `json:"is_escaped"` // 0:正常,1:逃跑
IsAi int32 `json:"is_ai"` // 0:普通用户,1:机器人
Role int32 `json:"role"` // 0:表示没有角色信息,玩家在游戏中的角色 游戏role 说明
Score int32 `json:"score"` // 玩家当前局得到的分数
IsWin int32 `json:"is_win"` // 结果 0:表示没有信息,1:输,2:赢,3:平局
Award int32 `json:"award"` // 奖励
Extras string `json:"extras"` // 扩展参数扩展说明
IsManaged int32 `json:"is_managed"` // 是否托管 0:未托管 1:托管
Diamond int64 `json:"diamond"` // 钻石收益,有可能负数,后期计算
LudoExtras *LudoExtras
}
type LudoExtras struct {
Color int `json:"color"`
Steps int `json:"steps"`
}
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddReportGameInfoEventSync(callback func(model *domain.Model, event interface{}) error) {
reportGameInfoEvent.SyncList = append(reportGameInfoEvent.SyncList, callback)
}
//加入到异步操作中
func AddReportGameInfoEventAsync(callback func(model *domain.Model, event interface{}) error) {
reportGameInfoEvent.AsyncList = append(reportGameInfoEvent.AsyncList, callback)
}
//领域事件发布
func PublishReportGameInfoEvent(model *domain.Model, event interface{}) error {
//执行同步的领域事件
for _, callback := range reportGameInfoEvent.SyncList {
if err := callback(model, event); err != nil {
return err
}
}
// 执行异步的领域事件
if len(reportGameInfoEvent.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range reportGameInfoEvent.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("ReportGameInfoEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package group_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
var groupInListen = new(event.Base)
// 进房事件
type GroupInEvent struct {
GroupId string // imGroupId
UserId mysql.ID
ExternalId string
Nick string
Avatar string
IsMember bool //是否永久成员
IsVip bool
NobleLevel uint16
}
func AddGroupInEventSync(callback func(model *domain.Model, event interface{}) error) {
groupInListen.SyncList = append(groupInListen.SyncList, callback)
}
func AddGroupInEventAsync(callback func(model *domain.Model, event interface{}) error) {
groupInListen.AsyncList = append(groupInListen.AsyncList, callback)
}
func PublishGroupInEvent(model *domain.Model, event interface{}) error {
// 执行同步的领域事件
for _, callback := range groupInListen.SyncList {
if err := callback(model, event); err != nil {
return myerr.WrapErr(err)
}
}
// 执行异步的领域事件
if len(groupInListen.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range groupInListen.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("GroupInEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package group_ev
import (
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/event"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
var groupLeaveListen = new(event.Base)
// 离房事件
type GroupLeaveEvent struct {
GroupId string
UserId mysql.ID
ExternalId string
}
func AddGroupLeaveEventSync(callback func(model *domain.Model, event interface{}) error) {
groupLeaveListen.SyncList = append(groupLeaveListen.SyncList, callback)
}
func AddGroupLeaveEventAsync(callback func(model *domain.Model, event interface{}) error) {
groupLeaveListen.AsyncList = append(groupLeaveListen.AsyncList, callback)
}
func PublishGroupLeaveEvent(model *domain.Model, event interface{}) error {
// 执行同步的领域事件
for _, callback := range groupLeaveListen.SyncList {
if err := callback(model, event); err != nil {
return myerr.WrapErr(err)
}
}
// 执行异步的领域事件
if len(groupLeaveListen.AsyncList) > 0 {
go func() {
defer _const.CheckGoPanic()
for _, callback := range groupLeaveListen.AsyncList {
// 异步事件需要用新model,主要是db
var newModel = domain.CreateModelContext(model.MyContext)
if err := callback(newModel, event); err != nil {
model.Log.Errorf("GroupInEvent aysnc fail:%v", err)
}
}
}()
}
return nil
}
package domain
import (
"gorm.io/gorm"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
)
type Model struct {
*CtxAndDb `gorm:"-"`
}
func CreateModel(ctxAndDb *CtxAndDb) *Model {
return &Model{CtxAndDb: ctxAndDb}
}
func CreateModelContext(myContext *mycontext.MyContext) *Model {
return &Model{
CtxAndDb: &CtxAndDb{
Db: mysql.Db,
MyContext: myContext,
Redis: redisCli.GetRedis(),
},
}
}
func CreateModelNil() *Model {
return &Model{
CtxAndDb: &CtxAndDb{
Db: mysql.Db,
MyContext: mycontext.CreateMyContext(nil),
Redis: redisCli.GetRedis(),
},
}
}
func (m *Model) DB() *gorm.DB {
return m.Db.WithContext(m)
}
// 包装事务
// 注意:需要使用新的model
func (m *Model) Transaction(f func(*Model) error) error {
// 公用context
// 新的db
txModel := CreateModelContext(m.MyContext)
txModel.Db = m.Db.Begin().WithContext(m)
err := f(txModel)
if err != nil {
txModel.Db.Rollback()
return err
}
return txModel.Db.Commit().Error
}
package bag_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm/clause"
"hilo-user/_const/enum/res_e"
"time"
)
type UserBag struct {
mysql.Entity
UserId mysql.ID
ResType mysql.Type // 资源类型 1:礼物
ResId mysql.ID
Count mysql.Num
EndTime time.Time
}
type UserBagDetail struct {
mysql.Entity
UserId mysql.ID
BagId mysql.ID
ResType mysql.Type // 资源类型 1:礼物
ResId mysql.ID
Count mysql.Num
AddReduce mysql.AddReduce
BefNum mysql.Num
AftNum mysql.Num
Remark mysql.Str
}
// 获取用户有效的背包
// param userId 用户id
// param resType 背包类型 1:礼物
// condition
// 1.获取end_time未到期的
// 2.数量大于0的
func GetUserValidUserBag(model *domain.Model, userId mysql.ID, resType res_e.ResUserBag) ([]*UserBag, error) {
var res []*UserBag
if err := model.DB().Model(UserBag{}).
Where("end_time > ?", time.Now()).
Where("count > 0").
Where("res_type = ?", resType).
Where("user_id = ?", userId).
Order("id").Find(&res).Error; err != nil {
return nil, err
}
return res, nil
}
// 获取指定背包
func GetUserBag(model *domain.Model, bagId mysql.ID) (*UserBag, error) {
res := new(UserBag)
if err := model.DB().Model(UserBag{}).
Where("id = ?", bagId).First(res).Error; err != nil {
return nil, err
}
return res, nil
}
// 增加用户背包
// param userId 用户id
// param resType 道具类型
// param resId 道具id
// param count 增加数量
// param day 增加天数
// condition:
// 0.事务操作
// 1.背包表
// 2.明细表
// return bagId
func AddUserBag(model *domain.Model, userId mysql.ID, resType mysql.Type, resId mysql.ID, count mysql.Num, day int, reason string) (mysql.ID, error) {
var bagId mysql.ID
err := model.Transaction(func(model *domain.Model) error {
// 1.背包表
endTime := time.Now().AddDate(0, 0, day)
userBag := &UserBag{
UserId: userId,
ResType: resType,
ResId: resId,
Count: count,
EndTime: endTime,
}
if err := model.DB().Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}, {Name: "res_type"}, {Name: "res_id"}, {Name: "end_time"}},
DoUpdates: clause.AssignmentColumns([]string{"count"}),
}).Create(userBag).Error; err != nil {
return err
}
bagId = userBag.ID // 自增id
// 2.明细表
userBagDetail := &UserBagDetail{
UserId: userId,
BagId: userBag.ID,
ResType: resType,
ResId: resId,
Count: count,
AddReduce: mysql.ADD,
BefNum: 0, // 加背包的统一为0
AftNum: count, // 加背包统一为count,因为每次加几乎不可能是一样的
Remark: reason,
}
if err := model.DB().Create(userBagDetail).Error; err != nil {
return err
}
return nil
})
return bagId, err
}
......@@ -3,11 +3,11 @@ 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"
"hilo-user/_const/redis_key"
"hilo-user/myerr"
"hilo-user/mylogrus"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
"time"
)
......
package diamond_m
import (
"hilo-user/_const/enum/diamond_e"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"strconv"
"time"
)
type DiamondAccount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondNum mysql.Num
PinkDiamondNum mysql.Num
Status diamond_e.StatusAccount
}
//账号详情
type DiamondAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
//账号操作配置
type DiamondOperateSet struct {
mysql.Entity
*domain.Model `gorm:"-"`
DiamondNum mysql.NumAll
FrequencyNum mysql.NumAll
FrequencyDay mysql.NumAll
DiamondMaxNum mysql.NumAll
AddReduce mysql.AddReduce
Type diamond_e.OperateType
Name mysql.Str
Status mysql.UserYesNo
DiamondType diamond_e.OperateType
}
//通过userId获取帐号
func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAccount, error) {
var diamondAccount DiamondAccount
if err := model.Db.WithContext(model).Where(&DiamondAccount{
UserId: userId,
}).First(&diamondAccount).Error; err != nil {
return nil, myerr.WrapErr(err)
}
diamondAccount.Model = model
return &diamondAccount, nil
}
//匹配条件扣费
func (diamondAccount *DiamondAccount) ChangeDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(operateType, originId, diamondNum)
}
//钻石操作记录,
func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
var diamondOperateSet DiamondOperateSet
var err error
if err = diamondAccount.Db.Where(&DiamondOperateSet{
Type: operateType,
Status: mysql.USER,
DiamondType: diamond_e.DiamondYellow,
}).First(&diamondOperateSet).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//判断是增加,账号是否被冻结
if diamondAccount.Status == diamond_e.Frozen && diamondOperateSet.AddReduce == mysql.REDUCE {
return nil, bizerr.DiamondAccountFrozen
}
//无限,检查次数
var count int64
if diamondOperateSet.FrequencyDay == -1 {
if diamondOperateSet.FrequencyNum != -1 {
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
}
}
} else if diamondOperateSet.FrequencyDay == 1 {
beginTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
if err != nil {
return nil, myerr.WrapErr(err)
}
//一天的次数
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Where("created_time >= ? ", beginTime).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
}
//终极拦截,利用
diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1) as n from diamond_account_detail d where d.user_id = " + strconv.FormatUint(diamondAccount.UserId, 10) + " and d.operate_type = " + strconv.FormatUint(uint64(operateType), 10) + " and d.created_time >= from_unixtime(" + strconv.FormatInt(getZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )")
}
//-1,代表值无效,由参数给与
var upateDiamondNum mysql.Num
if diamondOperateSet.DiamondNum == -1 {
upateDiamondNum = diamondNum
} else {
upateDiamondNum = mysql.Num(diamondOperateSet.DiamondNum)
}
var afterNum mysql.Num
if diamondOperateSet.AddReduce == mysql.ADD {
afterNum = diamondAccount.DiamondNum + upateDiamondNum
} else if diamondOperateSet.AddReduce == mysql.REDUCE {
if diamondAccount.DiamondNum < upateDiamondNum {
return nil, bizerr.DiamondNoEnough
}
afterNum = diamondAccount.DiamondNum - upateDiamondNum
} else {
return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(diamondOperateSet.AddReduce))
}
diamondAccountDetail := &DiamondAccountDetail{
Model: diamondAccount.Model,
UserId: diamondAccount.UserId,
DiamondAccountId: diamondAccount.ID,
OperateId: diamondOperateSet.ID,
OperateType: diamondOperateSet.Type,
OriginId: originId,
AddReduce: diamondOperateSet.AddReduce,
Num: upateDiamondNum,
Remark: diamondOperateSet.Name,
BefNum: diamondAccount.DiamondNum,
AftNum: afterNum,
diamondAccount: diamondAccount,
}
return diamondAccountDetail, err
}
package diamond_m
import (
"hilo-user/_const/enum/diamond_e"
"hilo-user/domain"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
)
func CheckEnoughDiamondFrozen(model *domain.Model, userId mysql.ID, diamondNum mysql.Num) (*DiamondAccount, error) {
diamondAccount, err := GetDiamondAccountByUserId(model, userId)
if err != nil {
return nil, err
}
if diamondAccount.DiamondNum < diamondNum {
return nil, bizerr.DiamondNoEnough
}
if diamondAccount.Status == diamond_e.Frozen {
return nil, bizerr.DiamondAccountFrozen
}
return diamondAccount, nil
}
package diamond_m
import (
"gorm.io/gorm"
"hilo-user/domain/model"
"hilo-user/myerr"
"hilo-user/mylogrus"
"hilo-user/resource/mysql"
"strconv"
)
func (diamondAccountDetail *DiamondAccountDetail) Persistent() error {
txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
}
if diamondAccountDetail.AddReduce == mysql.ADD {
//增加
txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num))
} else if diamondAccountDetail.AddReduce == mysql.REDUCE {
//减少,保证不能扣成负数
txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num))
} else {
myerr.NewSysError("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce)))
}
if err := txDiamondAccount.Error; err != nil {
return myerr.WrapErr(err)
}
if txDiamondAccount.RowsAffected == 0 {
mylogrus.MyLog.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
return myerr.NewWaring("gorm condition update.RowsAffected = 0")
}
//持久化diamondAccountDetail
if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
return myerr.WrapErr(err)
}
//改变diamondAccount值
if diamondAccountDetail.diamondAccount == nil {
return myerr.NewSysError("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID)))
}
var newDiamondAccount DiamondAccount
if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil {
return myerr.WrapErr(err)
}
if newDiamondAccount.DiamondNum < 0 {
return myerr.NewSysError("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID)))
}
return nil
}
package diamond_m
import "time"
func getZeroTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
package event_m
import (
"gorm.io/gorm"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time"
)
// 进房事件消息
type EventGroupIn struct {
mysql.Entity
*domain.Model `gorm:"-"`
Proto mysql.Type
Payload []byte
Mark mysql.YesNo
}
// 偏移值
type EventGroupInOffset struct {
mysql.Entity
*domain.Model `gorm:"-"`
MarkOffset mysql.ID
}
// 获取当前偏移值
func Offset(model *domain.Model) (*EventGroupInOffset, error) {
offset := new(EventGroupInOffset)
if err := model.Db.WithContext(model).First(offset).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("Offset fail:%v", err)
return nil, err
}
// gorm.ErrRecordNotFound
}
offset.Model = model
return offset, nil
}
// 批量获取进房事件
func FetchEventGroupIn(model *domain.Model, limit int) ([]*EventGroupIn, *EventGroupInOffset, error) {
offset, err := Offset(model)
if err != nil {
return nil, nil, err
}
var events []*EventGroupIn
if err := model.Db.WithContext(model).Model(EventGroupIn{}).
Where("id > ?", offset.MarkOffset).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchEventGroupIn fail:%v", err)
return nil, nil, err
}
return events, offset, nil
}
// 标记已完成
func (p *EventGroupIn) MarkDone() error {
p.Mark = mysql.YES
return p.Db.WithContext(p.Model).Model(EventGroupIn{}).Where("id = ?", p.ID).Update("mark", p.Mark).Limit(1).Error
}
// 查询过去1小时-5分钟前未mark的事件
// 用来补偿
// 记得加limit
func FetchUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupIn, error) {
offset, err := Offset(model)
if err != nil {
return nil, err
}
t := time.Now().Add(-time.Minute * 5)
lt := t.Add(-time.Hour)
var events []*EventGroupIn
if err := model.Db.WithContext(model).Model(EventGroupIn{}).
Where("mark = ?", mysql.NO).
Where("id <= ?", offset.MarkOffset).
Where("created_time < ?", t).
Where("created_time > ?", lt).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchUnMarkEvents fail:%v", err)
return nil, err
}
return events, nil
}
// 补偿加上unmark的event
func AddUnMarkEvent(model *domain.Model, event *EventGroupIn) error {
return model.Db.WithContext(model).Create(event).Error
}
package event_m
import (
"gorm.io/gorm"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time"
)
// 离房事件消息
type EventGroupLeave struct {
mysql.Entity
*domain.Model `gorm:"-"`
Proto mysql.Type
Payload []byte
Mark mysql.YesNo
}
// 偏移值
type EventGroupLeaveOffset struct {
mysql.Entity
*domain.Model `gorm:"-"`
MarkOffset mysql.ID
}
// 获取当前偏移值
func GroupLeaveOffset(model *domain.Model) (*EventGroupLeaveOffset, error) {
offset := new(EventGroupLeaveOffset)
if err := model.Db.WithContext(model).First(offset).Error; err != nil {
if err != gorm.ErrRecordNotFound {
model.Log.Errorf("Offset fail:%v", err)
return nil, err
}
// gorm.ErrRecordNotFound
}
offset.Model = model
return offset, nil
}
// 批量获取进房事件
func FetchEventGroupLeave(model *domain.Model, limit int) ([]*EventGroupLeave, *EventGroupLeaveOffset, error) {
offset, err := GroupLeaveOffset(model)
if err != nil {
return nil, nil, err
}
var events []*EventGroupLeave
if err := model.Db.WithContext(model).Model(EventGroupLeave{}).
Where("id > ?", offset.MarkOffset).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchEventGroupLeave fail:%v", err)
return nil, nil, err
}
return events, offset, nil
}
// 标记已完成
func (p *EventGroupLeave) MarkDone() error {
p.Mark = mysql.YES
return p.Db.WithContext(p.Model).Model(EventGroupLeave{}).Where("id = ?", p.ID).Update("mark", p.Mark).Limit(1).Error
}
// 查询过去1小时-5分钟前未mark的事件
// 用来补偿
// 记得加limit
func FetchGroupLeaveUnMarkEvents(model *domain.Model, limit int) ([]*EventGroupLeave, error) {
offset, err := GroupLeaveOffset(model)
if err != nil {
return nil, err
}
t := time.Now().Add(-time.Minute * 5)
lt := t.Add(-time.Hour)
var events []*EventGroupLeave
if err := model.Db.WithContext(model).Model(EventGroupLeave{}).
Where("mark = ?", mysql.NO).
Where("id <= ?", offset.MarkOffset).
Where("created_time < ?", t).
Where("created_time > ?", lt).
Order("id asc").Limit(limit).Find(&events).Error; err != nil {
model.Log.Errorf("FetchUnMarkEvents fail:%v", err)
return nil, err
}
return events, nil
}
// 补偿加上unmark的event
func AddGroupLeaveUnMarkEvent(model *domain.Model, event *EventGroupLeave) error {
return model.Db.WithContext(model).Create(event).Error
}
package event_m
import "hilo-user/domain/model"
func (p *EventGroupInOffset) Persistence() error {
return model.Persistent(p.Db, p)
}
func (p *EventGroupLeaveOffset) Persistence() error {
return model.Persistent(p.Db, p)
}
package user_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/user_e"
"hilo-user/common"
"hilo-user/domain"
"hilo-user/domain/event/user_ev"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"math/rand"
"strconv"
"time"
)
type GameInfo struct {
Id uint64 `json:"id"`
MgId string `json:"mg_id"`
GameType user_e.GameType `json:"user_type"`
Mode int32 `json:"mode"`
Piece int32 `json:"piece"`
OnOff1 uint8 `json:"on_off1"`
Diamond uint64 `json:"diamond"`
CreateId uint64 `json:"create_id"`
Status uint8 `json:"status"` // '0.未开始 1.游戏中 2.结束'
TxGroupId string `json:"tx_group_id"`
GameRoundId string `json:"user_round_id"`
BattleStartAt uint32 `json:"battle_start_at"`
BattleEndAt uint32 `json:"battle_end_at"`
BattleDuration uint32 `json:"battle_duration"`
AutoMatch uint8 `json:"auto_match"` // 是否开启自动匹配,0否1是
CreatedTime time.Time `json:"created_time"`
UpdatedTime time.Time `json:"updated_time"`
}
type GamePlayer struct {
Id uint64 `json:"id"`
GameId uint64 `json:"user_id"`
UserId uint64 `json:"user_id"`
Status uint8 `json:"status"` // '0.未开始 1.游戏中 2.游戏结束 3.逃跑 4.创建者关闭游戏',
UserCode string `json:"user_code"`
ExternalId string `json:"external_id"`
Rank uint32 `json:"rank"`
IsEscaped uint8 `json:"is_escaped"`
IsAi uint8 `json:"is_ai"`
Role int32 `json:"role"`
Score int32 `json:"score"`
IsWin uint8 `json:"is_win"`
Award uint32 `json:"award"`
Extras string `json:"extras"`
IsManaged uint8 `json:"is_managed"`
EndAt uint32 `json:"end_at"`
SeatIdx int8 `json:"seat_idx"`
Diamond int64 `json:"diamond"` // 黄钻收益,有可能负数
CreatedTime time.Time `json:"created_time"`
UpdatedTime time.Time `json:"updated_time"`
}
type GameAddParam struct {
GameId uint64 `form:"userId"`
GameType user_e.GameType `form:"userType" binding:"required"`
Mode user_e.GameMode `form:"mode" binding:"required"`
Piece int `form:"piece" binding:"required"`
OnOff1 int `form:"onOff1" binding:"required"`
Diamond uint64 `form:"diamond" binding:"required"`
AutoMatch int `form:"autoMatch" binding:"required"`
TxGroupId string `form:"groupId" binding:"required"`
GameCode string `form:"userCode"`
}
type GamePlayerOptLog struct {
Id uint64 `json:"id"`
GameId uint64 `json:"user_id"`
UserId uint64 `json:"user_id"`
Opt uint8 `json:"opt"`
TxGroupId string `json:"tx_group_id"`
CreateAt time.Time `json:"create_at"`
}
type GameSdkReport struct {
Id uint64 `json:"id"`
GameRoundId string `json:"user_round_id"`
TxGroupId string `json:"tx_group_id"`
ReportType string `json:"report_type"`
ReportMsg string `json:"report_msg"`
ExternalId string `json:"external_id"`
SsToken string `json:"ss_token"`
CreateAt time.Time `json:"create_at"`
}
func GetGameInfo(model *domain.Model, userId uint64, txGroupId, roundId string, battleEndAt, status int64) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
if userId != 0 {
db = db.Where("id = ?", userId)
}
if txGroupId != "" {
db = db.Where("tx_group_id = ?", txGroupId)
}
if roundId != "" {
db = db.Where("user_round_id = ?", roundId)
}
if battleEndAt != -1 {
db = db.Where("battle_end_at = ?", battleEndAt)
}
if status != -1 {
db = db.Where("status = ?", status)
}
err := db.First(&res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func GetGamingInfo(model *domain.Model, txGroupId string) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
if txGroupId != "" {
db = db.Where("tx_group_id = ?", txGroupId)
}
err := db.Where("status in (0,1)").First(&res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func Add(model *domain.Model, info *GameInfo) error {
nowTime := time.Now()
info.CreatedTime = nowTime
info.UpdatedTime = nowTime
err := model.Db.Save(info).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func Edit(model *domain.Model, id uint64, para *GameAddParam) error {
if id == 0 {
model.Log.Infof("GameDao Edit id = 0")
return nil
}
err := model.Db.Exec("update user_info set mode=?,piece=?,on_off1=?,diamond=?,auto_match=? where id = ? and battle_start_at = 0",
para.Mode, para.Piece, para.OnOff1, para.Diamond, para.AutoMatch, id).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GameCloseUpdate(model *domain.Model, info *GameInfo) error {
if info.Id == 0 {
model.Log.Infof("GameCloseUpdate Id = 0")
return bizerr.GameNotFound
}
result := model.Db.Exec("update user_info set status=?,battle_end_at=? where id = ? and status != 2",
user_e.GameStatusEnd, time.Now().Unix(), info.Id)
if result.Error != nil {
model.Log.Errorf("GameCloseUpdate info.Id:%v, err:%v", info.Id, result.Error)
return myerr.WrapErr(result.Error)
}
if result.RowsAffected <= 0 {
model.Log.Errorf("GameCloseUpdate info.Id:%v, err:%v", info.Id, result.Error)
return bizerr.GameCloseWrong
}
return nil
}
func GameCloseUpdatePlayer(model *domain.Model, info *GameInfo) error {
if info.Id == 0 {
model.Log.Infof("GameCloseUpdatePlayer Id = 0")
return nil
}
err := model.Db.Exec("update user_player set status=?,end_at=? where user_id = ?", user_e.GamerStatusEnd, time.Now().Unix(), info.Id).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GameStartUpdate(model *domain.Model, info *user_ev.GameStartObject) error {
//var initGameRoundId bool
userInfo := new(GameInfo)
infoKey, err := strconv.Atoi(info.ReportGameInfoKey)
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
}
err = model.Db.Where("id = ?", infoKey).First(&userInfo).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
//if err != gorm.ErrRecordNotFound {
// model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
// return myerr.WrapErr(err)
//}
//userInfo = new(GameInfo)
//err = model.Db.Where("tx_group_id = ? and user_round_id = ''", info.RoomId).First(&userInfo).Error
//if err != nil {
// if err != gorm.ErrRecordNotFound {
// model.Log.Errorf("GameStartUpdate err:%v, info:%v", err, info)
// return myerr.WrapErr(err)
// }
// model.Log.Infof("GameStartUpdate 找不到可以更新的记录 info:%v", info)
// return nil
//}
//initGameRoundId = true
}
if userInfo.Id == 0 {
model.Log.Errorf("GameStartUpdate 记录id为0 userInfo:%v", userInfo)
return myerr.WrapErr(bizerr.GameNotFound)
}
//if initGameRoundId {
// err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? and user_round_id='' limit 1",
// info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
//} else {
// err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? limit 1",
// info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
//}
err = model.Db.Exec("update user_info set mode=?,user_round_id=?,battle_start_at=? where id = ? limit 1",
info.GameMode, info.GameRoundId, info.BattleStartAt, userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v", err)
return myerr.WrapErr(err)
}
err = model.Db.Exec("update user_player set status=? where user_id = ?", user_e.GamerStatusGaming, userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameStartUpdate err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
// 标记游戏已经开始
func GameStartMark(model *domain.Model, userId mysql.ID) error {
if err := model.DB().Model(GameInfo{}).Where("id = ?", userId).Update("status", user_e.GameStatusGaming).Error; err != nil {
model.Log.Errorf("GameStartMark fail:userId:%v,err:%v", userId, err)
return err
}
return nil
}
// 标记游戏已经结束
func GameEndMark(model *domain.Model, userId mysql.ID) error {
if err := model.DB().Model(GameInfo{}).Where("id = ?", userId).Update("status", user_e.GameStatusEnd).Error; err != nil {
model.Log.Errorf("GameStartMark fail:userId:%v,err:%v", userId, err)
return err
}
return nil
}
func GameSettleUpdate(model *domain.Model, info *user_ev.GameSettleObject) error {
//if info.GameRoundId == "" {
// model.Log.Infof("GameSettleUpdate GameRoundId = 0")
// return nil
//}
infoKey, err := strconv.Atoi(info.ReportGameInfoKey)
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v, info:%v", err, info)
return myerr.WrapErr(err)
}
userInfo := new(GameInfo)
err = model.Db.Where("id = ?", infoKey).First(&userInfo).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
result := model.Db.Exec("update user_info set status=?,battle_end_at=?,battle_duration=? where id = ? and status=1",
user_e.GameStatusEnd, info.BattleEndAt, info.BattleDuration, userInfo.Id)
if result.Error != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
if result.RowsAffected <= 0 {
model.Log.Errorf("GameSettleUpdate 修改失败, userInfo.Id:%v", userInfo.Id)
return myerr.WrapErr(bizerr.GameSettleWrong)
}
for _, v := range info.Results {
err = model.Db.Exec("update user_player set status=?,`rank`=?,is_escaped=?,is_ai=?,`role`=?,score=?,is_win=?,"+
"award=?,extras=?,end_at=?,diamond=?,is_managed=? where user_id = ? and external_id = ?",
user_e.GamerStatusEnd, v.Rank, v.IsEscaped, v.IsAi, v.Role, v.Score, v.IsWin, v.Award, v.Extras, info.BattleEndAt,
v.Diamond, v.IsManaged, userInfo.Id, v.Uid).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
}
err = model.Db.Exec("update user_player set status=?,end_at=? where user_id=? and end_at=0",
user_e.GamerStatusEnd, time.Now().Unix(), userInfo.Id).Error
if err != nil {
model.Log.Errorf("GameSettleUpdate err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
func GetGamePlayers(model *domain.Model, userId uint64) ([]*GamePlayer, error) {
res := make([]*GamePlayer, 0)
err := model.Db.Where("user_id = ?", userId).Order("created_time").Find(&res).Error
if err != nil {
return nil, err
}
return res, nil
}
func DelGamePlayers(model *domain.Model, userId uint64) error {
if userId <= 0 {
return bizerr.InvalidParameter
}
err := model.Db.Exec("delete from user_player where user_id = ?", userId).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GetGamePlayersMap(model *domain.Model, userId uint64, userExtIds []string) (map[string]*GamePlayer, error) {
list := make([]*GamePlayer, 0, len(userExtIds))
err := model.Db.Where("user_id = ? and external_id in (?)", userId, userExtIds).Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
res := make(map[string]*GamePlayer, 0)
for _, v := range list {
res[v.ExternalId] = v
}
return res, nil
}
func GetGamePlayer(model *domain.Model, userId, userId uint64) (*GamePlayer, error) {
res := new(GamePlayer)
err := model.Db.Where("user_id = ? and user_id = ?", userId, userId).First(res).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return res, nil
}
func SaveGamePlayer(model *domain.Model, info *GamePlayer) error {
err := model.Db.Save(info).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func DelGamePlayer(model *domain.Model, id uint64) error {
result := model.Db.Exec("delete from user_player where id = ? and status=0", id)
if result.Error != nil {
return result.Error
}
if result.RowsAffected <= 0 {
return myerr.WrapErr(bizerr.GameExitWrong)
}
return nil
}
func UpdateGamePlayerExit(model *domain.Model, id uint64) error {
err := model.Db.Exec("update user_player set end_at=? where id = ?", time.Now().Unix(), id).Error
if err != nil {
return err
}
return nil
}
func SaveGameOptLog(model *domain.Model, userId, userId uint64, opt user_e.GameOpt, txGroupId string) error {
defer common.CheckGoPanic()
err := model.Db.Save(&GamePlayerOptLog{GameId: userId, UserId: userId, Opt: uint8(opt), TxGroupId: txGroupId, CreateAt: time.Now()}).Error
if err != nil {
model.Log.Errorf("SaveGameOptLog err:%v", err)
return err
}
return nil
}
func SaveGameSdkReport(model *domain.Model, userRoundId, roomId, reportType, reportMsg, externalId, ssToken string) error {
defer common.CheckGoPanic()
err := model.Db.Save(&GameSdkReport{TxGroupId: roomId, GameRoundId: userRoundId, ReportType: reportType,
ReportMsg: reportMsg, ExternalId: externalId, SsToken: ssToken, CreateAt: time.Now()}).Error
if err != nil {
model.Log.Errorf("SaveGameSdkReport err:%v", err)
return err
}
return nil
}
// 获取一个正在进行游戏的房间id(房间没有密码,没有下注的游戏房间)
func GetGamingTxGroupId(model *domain.Model, userType user_e.GameType) (txGroupId string, err error) {
// 游戏类型,游戏未满人,游戏未开始
infos := make([]*GameInfo, 0)
sql := "select s1.* from (select * from user_info where user_type=? and status=0 and diamond=0 limit 50) s1 left join group_info on s1.tx_group_id=group_info.tx_group_id where group_info.password='' and group_info.tourist_mic=1"
err = model.Db.Raw(sql, userType).Find(&infos).Error
//err = model.Db.Where("status = 0 and user_type = ?", userType).Limit(10).Find(&infos).Error
if err != nil {
return
}
if len(infos) == 0 {
return
}
if len(infos) == 1 {
txGroupId = infos[0].TxGroupId
return
}
// 打乱
rand.Shuffle(len(infos), func(i, j int) {
t := infos[i]
infos[i] = infos[j]
infos[j] = t
})
txGroupId = infos[0].TxGroupId
return
}
// 获取用户在该房间已经加入的未结束的游戏
func GetGamingInfoByUserId(model *domain.Model, userId uint64, txGroupId string) (*GameInfo, error) {
res := new(GameInfo)
db := model.Db
err := db.Where("id in (select user_id from user_player where user_id=? and end_at=0) and tx_group_id = ? and status in (0,1)", userId, txGroupId).First(&res).Error
//err := db.Where("status in (0,1)").First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return res, nil
}
package user_m
import (
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/resource/mysql"
"sort"
"time"
)
type StartGamePlayer struct {
TxGroupId mysql.Str // 房间id
GameId mysql.ID // 游戏id
MgId mysql.Str // 游戏sdk id
UserId mysql.ID // 用户id
CreatedTime time.Time // 加入游戏时间
}
// 获取可以开始的游戏
// condition
// 1. 游戏还没开始
// 2. 游戏人数大于等于2个
// 3. 第二个加入的人距离现在已经超过15秒
func GetCanStartGames(model *domain.Model) []GameInfo {
// 1. 游戏还没开始
sql := "SELECT g.tx_group_id,p.user_id,g.mg_id,p.user_id,p.created_time FROM `user_info` g,`user_player` p where p.user_id = g.id AND g.`status` = ?;"
var startGamePlayers []StartGamePlayer
if err := model.DB().Raw(sql, user_e.GameStatusNoStart).Find(&startGamePlayers).Error; err != nil {
model.Log.Errorf("GetCanStartGames fail,sql:%v,err:%v", sql, err)
return nil
}
// userId -> userPlayer
var startGamePlayersMap = make(map[mysql.ID][]StartGamePlayer)
for i, p := range startGamePlayers {
startGamePlayersMap[p.GameId] = append(startGamePlayersMap[p.GameId], startGamePlayers[i])
}
var res []GameInfo
for userId, players := range startGamePlayersMap {
// 2. 游戏人数大于等于2个
if len(players) < 2 {
continue
}
model.Log.Infof("startGamePlayer,userId:%v,player:%+v", userId, players)
// 3. 第二个加入的人距离现在已经超过15秒
sort.Slice(players, func(i, j int) bool {
return players[i].CreatedTime.Before(players[j].CreatedTime)
})
// 客户端15秒,服务端延迟1秒
if time.Now().Sub(players[1].CreatedTime).Seconds() >= 16 {
res = append(res, GameInfo{
Id: userId,
MgId: players[1].MgId,
TxGroupId: players[1].TxGroupId,
})
}
}
return res
}
package user_m
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"hilo-user/_const/enum/robot_e"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/cache/robot_c"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/user_m"
"hilo-user/resource/config"
"hilo-user/resource/mysql"
"hilo-user/rpc"
"time"
)
// 机器人
type GameRobot struct {
mysql.Entity
UserId mysql.ID // 用户id
State robot_e.RobotState // 机器人状态
OpStep robot_e.RobotOp // 当前所在步骤
GroupId string // 群组id
MicIndex int // 麦位
GameUid mysql.ID // 游戏id
MgId string // sdk游戏Id
LastUseTime time.Time // 上次使用的时间
model *domain.Model `gorm:"-"` // db、ctx
Game GameTiny `gorm:"-"` // 需要加入的游戏
User user_m.User `gorm:"-"` // 用户信息
Group *group_m.GroupInfo `gorm:"-"` // 群组信息
Token string `gorm:"-"` // jwt token
Over bool `gorm:"-"` // 是否结束
Err error `gorm:"-"` // 错误日志
// service层的GameOpt
GameOpt func(userId, userId uint64, code, ext, lang, userCode, txGroupId string, opt user_e.GameOpt, seatIdx int8, isAi bool) error `gorm:"-"`
}
// 机器人日志
type GameRobotLog struct {
mysql.Entity
RobotUid mysql.ID
Op robot_e.RobotOp // 机器人操作
DataId string // 房间号 or 麦位 or 游戏id
}
// 标记正在使用中
func (robot *GameRobot) MarkUsing(model *domain.Model) error {
updates := map[string]interface{}{
"state": robot_e.RobotStateUsing,
"last_use_time": time.Now(),
}
return model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
}
// 标记闲置
func (robot *GameRobot) MarkIdle(model *domain.Model) {
updates := map[string]interface{}{
"state": robot_e.RobotStateIdle,
"group_id": "",
"mic_index": -1,
"user_uid": 0,
"mg_id": "",
"op_step": robot_e.RobotOpNone,
}
if err := model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error; err != nil {
robot.model.Log.Errorf("MarkIdle fail:%v", err)
}
}
// 机器人干活了
func (robot *GameRobot) Run() {
robot.model = domain.CreateModelNil()
robot.model.Log = robot.model.Log.WithField("GameRobotRun", robot.ID)
var err error
defer func() {
if err != nil {
robot.model.Log.Errorf("Run fail,robotId:%v,uid:%v,err:%v", robot.ID, robot.UserId, err)
// reset to idle
robot.MarkIdle(robot.model)
robot.Over = true
robot.Err = err
}
}()
// 检查游戏状态
if robot.Game.Status == user_e.GameStatusNoStart { // 未开始
go robot.heartbeat() // 心跳自愈
// 进入游戏流程
switch robot.OpStep {
case robot_e.RobotOpNone:
if err = robot.GroupIn(); err != nil {
return
}
fallthrough
case robot_e.RobotOpGroupIn:
if err = robot.MicIn(); err != nil {
return
}
fallthrough
case robot_e.RobotOpMicIn:
if err = robot.GameIn(); err != nil {
return
}
fallthrough
default:
robot.model.Log.Infof("may in other step:%v", robot.OpStep)
}
} else {
robot.model.Log.Warnf("user status not normal:%v", robot.Game)
}
}
// 进程重启后的机器人自愈
// 如果走过进入游戏了,则继续走心跳逻辑
// 否则,直接走
func (robot *GameRobot) ReRun() {
robot.model = domain.CreateModelNil()
robot.model.Log = robot.model.Log.WithField("GameRobotReRun", robot.ID)
if robot.GameUid > 0 {
go robot.heartbeat()
} else {
robot.Leave("ReRun")
}
}
// 进房
func (robot *GameRobot) GroupIn() error {
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/in"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupId": robot.Game.GroupId,
}
// http to biz
if resp, err := rpc.HttpPutForm(robot.model, url, header, form); err != nil {
return err
} else {
type GroupInResp struct {
Code int `json:"code"`
}
res := new(GroupInResp)
if err = json.Unmarshal(resp, res); err != nil {
return err
} else {
if res.Code != 200 {
return errors.New(fmt.Sprintf("Group In Not 200:%v", res))
} else {
// 复制群组id
robot.GroupId = robot.Game.GroupId
}
}
}
// no error
return robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"group_id": robot.GroupId,
"op_step": robot_e.RobotOpGroupIn,
}
err := txModel.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGroupIn,
DataId: robot.GroupId,
}).Error
})
}
// 上麦
func (robot *GameRobot) MicIn() error {
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/mic/in"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupUuid": robot.GroupId,
"i": "", // 空则随意上一个空位置
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("Mic In fail:%v", err)
return err
} else {
type MicInResp struct {
Code int `json:"code"`
Data struct {
MicIndex int `json:"micIndex"`
} `json:"data"`
}
res := new(MicInResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Mic In json:%v", res))
return err
} else {
if res.Code != 200 || res.Data.MicIndex < 0 {
robot.model.Log.Errorf(fmt.Sprintf("Mic In Not 200:%v,groupId:%v", res, robot.GroupId))
if res.Code == 12008 {
// 群上麦失败,群先做cd,能上麦的情况太多
_ = robot_c.CDMicInGroup(robot.model, robot.GroupId)
}
return errors.New(fmt.Sprintf("Mic In Not 200:%v", res))
} else {
robot.MicIndex = res.Data.MicIndex // 赋值麦位
}
}
}
return robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"mic_index": robot.MicIndex,
"op_step": robot_e.RobotOpMicIn,
}
err := robot.model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpMicIn,
DataId: fmt.Sprintf("%s-%d", robot.GroupId, robot.MicIndex),
}).Error
})
}
// 加入游戏
func (robot *GameRobot) GameIn() error {
if err := robot.GameOpt(robot.UserId, robot.Game.GameUid, robot.User.Code, robot.User.ExternalId, "en", "", robot.GroupId, user_e.GameOptJoin, -1, true); err != nil {
robot.model.Log.Errorf("Game In fail,userId:%v,err:%v", robot.UserId, err)
return err
}
err := robot.model.Transaction(func(txModel *domain.Model) error {
updates := map[string]interface{}{
"user_uid": robot.Game.GameUid,
"mg_id": robot.Game.MgId,
"op_step": robot_e.RobotOpGameIn,
}
err := robot.model.Db.Model(GameRobot{}).Where("id = ?", robot.ID).
Updates(updates).Error
if err != nil {
return err
}
// 赋值游戏id
robot.GameUid = robot.Game.GameUid
return txModel.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGameIn,
DataId: fmt.Sprintf("%d", robot.GameUid),
}).Error
})
if err != nil {
return err
}
// GameIn成功之后腾讯云通知
robot.TxGroupInPush()
return nil
}
// 机器人离开
// 下麦+离开房间+退出游戏
func (robot *GameRobot) Leave(reason string) {
// 异常情况会直接leave,保护一下model未赋值
if robot.model == nil {
robot.model = domain.CreateModelNil()
}
robot.model.Log.Infof("robot leave,id:%v,reason:%v", robot.ID, reason)
robot.MicLeave()
robot.GroupLeave()
robot.GameOut()
robot.MarkIdle(robot.model)
}
// 下麦
func (robot *GameRobot) MicLeave() {
// 未上麦
if robot.MicIndex < 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/mic/leave"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupUuid": robot.GroupId,
"i": fmt.Sprintf("%d", robot.MicIndex), //
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("Mic Leave fail:%v", err)
return
} else {
type MicLeaveResp struct {
Code int `json:"code"`
}
res := new(MicLeaveResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Mic Leave json:%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("Mic Leave Not 200:%v", res))
}
}
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpMicLeave,
DataId: fmt.Sprintf("%s-%d", robot.GroupId, robot.MicIndex),
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 离房
func (robot *GameRobot) GroupLeave() {
if len(robot.GroupId) <= 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/v1/imGroup/leave"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"groupId": robot.GroupId,
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("GroupLeave fail:%v", err)
return
} else {
type GroupLeaveResp struct {
Code int `json:"code"`
}
res := new(GroupLeaveResp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("Group Leave json :%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("Group Leave Not 200:%v", res))
}
}
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGroupLeave,
DataId: robot.GroupId,
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 离开游戏
func (robot *GameRobot) GameOut() {
if robot.GameUid <= 0 || len(robot.GroupId) <= 0 {
return
}
if err := robot.GameOpt(robot.UserId, robot.GameUid, robot.User.Code, robot.User.ExternalId, "en", "", robot.GroupId, user_e.GameOptExit, -1, true); err != nil {
robot.model.Log.Errorf("Game Out fail,userId:%v,err:%v", robot.UserId, err)
return
}
if err := robot.model.Db.Create(&GameRobotLog{
RobotUid: robot.ID,
Op: robot_e.RobotOpGameOut,
DataId: fmt.Sprintf("%d", robot.GameUid),
}).Error; err != nil {
robot.model.Log.Errorf("log fail:%v", err)
}
}
// 腾讯云麦位通知
func (robot *GameRobot) TxGroupInPush() {
if robot.Group == nil || robot.User.ID <= 0 {
return
}
url := config.GetUrlConfig().BIZ_HTTP + "/inner/micAllRPush"
header := map[string]string{
"nonce": "hilo",
"token": robot.Token,
}
form := map[string]string{
"imGroupId": robot.Group.ImGroupId,
"externalId": robot.User.ExternalId,
}
// http to biz
if resp, err := rpc.HttpPostForm(robot.model, url, header, form); err != nil {
robot.model.Log.Errorf("GroupLeave fail:%v", err)
return
} else {
type Resp struct {
Code int `json:"code"`
}
res := new(Resp)
if err = json.Unmarshal(resp, res); err != nil {
robot.model.Log.Errorf(fmt.Sprintf("TxGroupInPush json :%v", res))
return
} else {
if res.Code != 200 {
robot.model.Log.Errorf(fmt.Sprintf("TxGroupInPush Not 200:%v", res))
}
}
}
}
// 机器人心跳自愈
func (robot *GameRobot) heartbeat() {
// robot.GameUid是mysql/执行完加入游戏才有
userId := robot.GameUid
if userId <= 0 {
// 这里是未加入游戏前的userId
userId = robot.Game.GameUid
}
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
user, err := getGameInfo(robot.model, userId)
if robot.Over || err != nil || user_e.GameStatus(user.Status) == user_e.GameStatusEnd {
robot.Leave("robot over")
return
}
}
}
}
// 根据id获取游戏信息
func getGameInfo(model *domain.Model, userUid mysql.ID) (*GameInfo, error) {
user := new(GameInfo)
err := model.DB().Model(user).Where("id = ?", userUid).First(user).Error
return user, err
}
package user_m
import (
"hilo-user/_const/enum/robot_e"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/cache/robot_c"
"hilo-user/resource/mysql"
"math/rand"
"time"
)
// 游戏结构体
type GameTiny struct {
GameUid mysql.ID
GameType user_e.GameType
GroupId string
MgId int64
Diamond int64
NeedRobots int // 需要机器人数量
Status user_e.GameStatus // 游戏进行状态,1:进行中、0:结束, 心跳实时刷新
UpdatedTime time.Time
}
// 获取需要机器人的游戏
func GetNeedRobotGames(model *domain.Model) ([]GameTiny, error) {
var resGames []GameTiny
// 获取准备开始的游戏
var users []GameTiny
sql := "SELECT user.id as user_uid,user.user_type,user.tx_group_id as group_id,mg_id,user.diamond,user.`status`,user.updated_time FROM user_info user,group_info g " +
"WHERE user.tx_group_id = g.tx_group_id AND user. STATUS = 0 AND user.auto_match = 1 AND user.battle_start_at = 0 AND g.`password` = '' AND g.tourist_mic = 1"
if err := model.DB().Raw(sql).Find(&users).Error; err != nil {
return nil, err
}
now := time.Now()
for _, user := range users {
// 使用user.UpdatedTime(非CreatedTime)去判断8秒,兼容编辑游戏的情况
if now.Sub(user.UpdatedTime).Seconds() <= 8 {
continue
}
// user players
var players []GamePlayer
if err := model.DB().Model(GamePlayer{}).
Where("user_id = ?", user.GameUid).Find(&players).Error; err == nil {
// 没有玩家,属于异常的user
if len(players) <= 0 {
model.Log.Errorf("GetNeedRobotGames no player exits,user:%v,players:%v", user, players)
continue
}
// 玩家大于2个就不需要机器人
if len(players) > 1 {
continue
}
// 机器人进群cd中
if robot_c.IsGroupInCd(model, user.GroupId) {
model.Log.Warnf("IsGroupInCd in cd,user:%v", user)
continue
}
var needRobots = 1 // 一个机器人
resGames = append(resGames, GameTiny{
GameUid: user.GameUid,
GroupId: user.GroupId,
MgId: user.MgId,
NeedRobots: needRobots,
Status: user.Status,
GameType: user.GameType,
Diamond: user.Diamond,
})
} else if err != nil {
model.Log.Errorf("GamePlayer fail:%v", err.Error())
}
}
return resGames, nil
}
// 获取正在使用中的机器人
func GetUsingRobots(model *domain.Model) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("state = ?", robot_e.RobotStateUsing).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取房间中的机器人
func GetRoomRobots(model *domain.Model, txGroupId mysql.Str) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("group_id = ?", txGroupId).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取异常的robot
// state = 0,但是状态没清空
func GetAbnormalRobots(model *domain.Model) ([]*GameRobot, error) {
var robots []*GameRobot
if err := model.DB().Model(GameRobot{}).Where("state = ? AND op_step != 0", robot_e.RobotStateIdle).Find(&robots).Error; err != nil {
return nil, err
}
return robots, nil
}
// 获取闲置中的机器人
// 并且设置为使用中
func GetSetIdleGameRobots(model *domain.Model, num int) ([]*GameRobot, error) {
if num <= 0 {
model.Log.Warnf("GetSetIdleGameRobots no need robot:%v", num)
return nil, nil
}
var robots []*GameRobot
var canUseRobots []*GameRobot
err := model.Transaction(func(txModel *domain.Model) error {
if err := txModel.Db.WithContext(txModel).Model(GameRobot{}).Where("state = ?", robot_e.RobotStateIdle).Limit(1000).Find(&robots).Error; err != nil {
return err
}
// 打乱1000个空闲的机器人
rand.Shuffle(len(robots), func(i, j int) {
robots[i], robots[j] = robots[j], robots[i]
})
for i, robot := range robots {
// 增加cd逻辑,60秒机器人不复用
if time.Now().Sub(robot.LastUseTime).Seconds() < 60 {
model.Log.Warnf("robot cannot frequency use:%v", robot)
continue
}
if err := robot.MarkUsing(txModel); err != nil {
return err
}
canUseRobots = append(canUseRobots, robots[i])
num--
if num <= 0 {
break
}
}
return nil
})
if err != nil {
model.Log.Errorf("GetIdleGameRobots fail:%v", err)
return nil, err
}
return canUseRobots, nil
}
// 游戏ai启动
func AddAi(model *domain.Model, robots []*GameRobot) {
for _, robot := range robots {
robot.Run() // 一个机器人一个协程
}
}
package groupPower_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/groupPower_e"
"hilo-user/domain"
"hilo-user/domain/model/group_m"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
type GroupPower struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupUid mysql.Str
Name mysql.Str
Status groupPower_e.GroupPowerStatus
}
type GroupPowerUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
GroupPowerId mysql.ID
UserId mysql.ID
Role groupPower_e.GroupPowerUserRole
}
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
}
//获取用户所在的国家势力信息,不存在则为nil
func GetGroupPowerUserOrNil(model *domain.Model, userId mysql.ID) (*GroupPowerUser, error) {
groupPowerUser := GroupPowerUser{}
if err := model.Db.Where(&GroupPowerUser{
UserId: userId,
}).First(&groupPowerUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
groupPowerUser.Model = model
return &groupPowerUser, nil
}
// 查询用户加入的国家势力ID及名称(势力绑定的群组的名称)
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 group_m
import (
"context"
"encoding/json"
redisV8 "github.com/go-redis/redis/v8"
"gorm.io/gorm"
"hilo-user/common"
"hilo-user/common/rediskey"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
)
type GroupRoles struct {
mysql.Entity
UserId uint64
ImGroupId string
Role common.GroupRoleType
}
func (this *GroupInfo) TableName() string {
return "group_info"
}
//发言,注意(发言是在麦位上)
type MicUser struct {
model *domain.Model
//群组uuid
GroupUuid string
//麦位
I int
//麦中的人
ExternalId string
//
UserId uint64
//静音 true:静音,false:没有静音
Forbid bool
//上麦的的时间戳
Timestamp int64
}
//记录麦位上有谁。用于
type UserInMic struct {
//群组uuid
GroupUuid string
//麦位
I int
//userId
UserId uint64
}
// 查询用户在IM群组中的角色
func GetRoleInGroup(model *domain.Model, userId uint64, imGroupId string) (uint16, error) {
r := GroupRoles{}
err := model.Db.Where(&GroupRoles{
UserId: userId,
ImGroupId: imGroupId}).First(&r).Error
if err != nil {
if err != gorm.ErrRecordNotFound {
return 0, err
} else {
return 0, nil
}
}
return r.Role, nil
}
func GetByTxGroupId(model *domain.Model, txGroupId string) (*GroupInfo, error) {
if len(txGroupId) <= 0 {
return nil, bizerr.GroupNotFound
}
res := new(GroupInfo)
err := model.Db.Where(&GroupInfo{TxGroupId: txGroupId}).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(bizerr.GroupNotFound)
} else {
return nil, myerr.WrapErr(err)
}
}
return res, nil
}
//获取用户在哪个麦位上。没有不在麦上,则是nil
func GetMicUserByExternalId(model *domain.Model, externalId string) (*MicUser, error) {
if str, err := redisCli.GetRedis().Get(context.Background(), rediskey.GetPrefixGroupUserInMic(externalId)).Result(); err != nil {
if err != redisV8.Nil {
return nil, myerr.WrapErr(err)
} else {
return nil, nil
}
} else {
if userInMic, err := strToUserInMic(str); err != nil {
return nil, err
} else {
return GetMicUser(model, userInMic.GroupUuid, userInMic.I)
}
}
}
//麦位上没人,返回nil
func GetMicUser(model *domain.Model, groupUuid string, i int) (*MicUser, error) {
if i < 1 || i > 30 {
return nil, myerr.NewSysErrorF("麦序不对,不在范围值内 i:%v", i)
}
str, err := redisCli.GetRedis().Get(context.Background(), rediskey.GetPrefixGroupMicUser(groupUuid, i)).Result()
if err != nil {
if err == redisV8.Nil {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
var micUser MicUser
err = json.Unmarshal([]byte(str), &micUser)
if err != nil {
return nil, err
}
return &MicUser{
model: model,
GroupUuid: groupUuid,
I: i,
ExternalId: micUser.ExternalId,
UserId: micUser.UserId,
Forbid: micUser.Forbid,
Timestamp: micUser.Timestamp,
}, nil
}
func strToUserInMic(str string) (UserInMic, error) {
userInMic := UserInMic{}
if err := json.Unmarshal([]byte(str), &userInMic); err != nil {
return UserInMic{}, myerr.WrapErr(err)
}
return userInMic, nil
}
package group_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/group_e"
"hilo-user/domain"
"hilo-user/myerr/bizerr"
"time"
)
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 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 GetGroupInfoByOwner(model *domain.Model, userId uint64) (*GroupInfo, error) {
if userId <= 0 {
return nil, bizerr.GroupNotFound
}
r := GroupInfo{}
err := model.Db.Where(&GroupInfo{Owner: userId}).First(&r).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, err
}
}
return &r, nil
}
package group_m
import (
"hilo-user/domain"
"hilo-user/myerr/bizerr"
)
func ToTxGroupId(model *domain.Model, imGroupId string) (string, error) {
if len(imGroupId) <= 0 {
return "", nil
}
gi, err := GetGroupInfo(model, imGroupId)
if err != nil {
return "", err
}
if gi == nil {
return "", bizerr.GroupNotFound
}
return gi.TxGroupId, nil
}
package group_m
import (
"encoding/json"
"hilo-user/_const/enum/group_e"
"hilo-user/domain"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/user_m"
"hilo-user/rpc"
)
// 信令消息
type GroupSystemMsg struct {
MsgId group_e.TypeSignalMsg `json:"msgId"`
Source string `json:"source"`
Target string `json:"target"`
Content string `json:"content"`
}
type HiloUserInfo struct {
WealthGrade uint32 `json:"wealthGrade"`
CharmGrade uint32 `json:"charmGrade"`
IsVip bool `json:"isVip"`
IsPretty bool `json:"isPretty"`
Medals []uint32 `json:"medals"`
PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称
NobleLevel uint16 `json:"nobleLevel"`
SvipLevel int `json:"svipLevel"`
}
var GetGroupPowerNameByUserId func(model *domain.Model, userId uint64) (uint64, string, error)
//不用返回错误
func GetHiloUserInfo(model *domain.Model, extId string) string {
user, err := user_m.GetUserByExtId(model, extId)
if err != nil {
model.Log.Errorf("extId:%v, err:%+v", extId, err)
return ""
}
wealthGrade, _, err := user_m.GetWealthGrade(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
charmGrade, _, err := user_m.GetCharmGrade(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
isVip, _, err := user_m.IsVip(user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
//
isPretty := user.IsPrettyCode()
//
medals, err := user_m.GetUserMedalMerge(model.Log, model.Db, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
_, powerName, err := GetGroupPowerNameByUserId(model, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
nobleLevel, err := noble_m.GetNobleLevel(model.Db, user.ID)
if err != nil {
model.Log.Errorf("extId:%v, err:%v", extId, err)
return ""
}
svip, _ := rpc.GetUserSvip(model, user.ID)
hilo := HiloUserInfo{
WealthGrade: wealthGrade,
CharmGrade: charmGrade,
IsVip: isVip,
IsPretty: isPretty,
Medals: medals,
PowerName: powerName,
NobleLevel: nobleLevel,
SvipLevel: svip.SvipLevel,
}
buf, err := json.Marshal(hilo)
if err != nil {
model.Log.Errorf("hilo:%+v, err:%v", hilo, err)
}
return string(buf)
}
package msg_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
)
func GetMsgSysRecordInit(model *domain.Model, t uint32, msgSysId uint64) *MsgSysRecord {
return &MsgSysRecord{
Model: model,
Type: t,
Status: mysql.EXIST,
MsgSysId: msgSysId,
}
}
func GetMsgSysRecord(model *domain.Model, msgSysId uint64) (*MsgSysRecord, error) {
msgSysRecord := MsgSysRecord{}
if err := model.Db.Model(&MsgSysRecord{}).Where(&MsgSysRecord{
MsgSysId: msgSysId,
}).First(&msgSysRecord).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
} else {
msgSysRecord.Model = model
return &msgSysRecord, nil
}
}
package msg_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/sdk/emas"
"git.hilo.cn/hilo-common/utils"
"hilo-user/_const/enum/msg_e"
)
type MsgUserRecord struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Type msg_e.MsgUserRecordType
Nick mysql.Str
NickUserId mysql.ID //用户的别名
DiamondIncome mysql.Str
DayNum mysql.Str //多少天
PropertyUrl mysql.Str //道具地址
BeanNum mysql.Str //多少豆子
GroupCode mysql.Str //群组code
}
type MsgSysRecord struct {
mysql.Entity
*domain.Model `gorm:"-"`
//Type msg_m.MsgSysRecordType
Type uint32
Status mysql.LogicDel
MsgSysId mysql.ID
}
//系统消息,用户最后已读的位置
type MsgSysUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
Type msg_e.MsgSysUserType
UserId mysql.ID
MsgSysLastId mysql.ID
}
//删除
func (msgSysRecord *MsgSysRecord) Del() *MsgSysRecord {
msgSysRecord.Status = mysql.DEL
return msgSysRecord
}
type MsgReceive struct {
Type msg_e.MsgReceiveType `json:"type"`
//Timestamp mysql.Timestamp `json:"timestamp"`
}
func NewUserRecord(model *domain.Model, userId mysql.ID, t msg_e.MsgUserRecordType, nick mysql.Str, nickUserId mysql.ID, diamondIncome mysql.Str, dayNum mysql.Str, propertyUrl mysql.Str, beanNum mysql.Str, groupCode mysql.Str) *MsgUserRecord {
return &MsgUserRecord{
Model: model,
UserId: userId,
Type: t,
Nick: nick,
NickUserId: nickUserId,
DiamondIncome: diamondIncome,
DayNum: dayNum,
PropertyUrl: propertyUrl,
BeanNum: beanNum,
GroupCode: groupCode,
}
}
// 发给小助手的消息, 不需要抛出错误
func SendEmasMsgAssistant(model *domain.Model, externalId string, deviceType string) error {
str, _ := utils.ToString(MsgReceive{
Type: msg_e.UserMsgReceiveType,
})
err := emas.SendMsg(externalId, deviceType, str)
if err != nil {
model.Log.Errorf("emas.SendMsg err:%v", err)
}
return nil
}
package msg_m
import (
"hilo-user/domain/model"
"hilo-user/myerr"
)
func (msgUserRecord *MsgUserRecord) Persistent() error {
if err := model.Persistent(msgUserRecord.Db, msgUserRecord); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (msgSysRecord *MsgSysRecord) Persistent() error {
if err := model.Persistent(msgSysRecord.Db, msgSysRecord); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (msgSysUser *MsgSysUser) Persistent() error {
return model.Persistent(msgSysUser.Db, msgSysUser)
}
\ No newline at end of file
package noble_m
import (
"gorm.io/gorm"
"time"
)
const RENEWAL_LIMIT_DAY = 7
type ResNoble struct {
Level uint16
PurchasePrice uint32
RenewalPrice uint32
Duration uint16
PicUrl string
DailyGold uint
RideId uint64 // 赠送的座驾ID
HeaddressId uint64 // 赠送的头饰ID
}
func GetAllConfig(db *gorm.DB) ([]ResNoble, error) {
rows := make([]ResNoble, 0)
err := db.Find(&rows).Error
if err != nil {
return nil, err
}
return rows, nil
}
func GetAllConfigMap(db *gorm.DB) (map[uint16]ResNoble, error) {
rows, err := GetAllConfig(db)
if err != nil {
return nil, err
}
result := make(map[uint16]ResNoble, 0)
for _, i := range rows {
result[i.Level] = i
}
return result, nil
}
func GetConfigByLevel(db *gorm.DB, level uint16) (ResNoble, error) {
r := ResNoble{}
if err := db.Model(&ResNoble{}).First(&r, level).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return r, nil
} else {
return r, err
}
}
return r, nil
}
// 根据过期时间推算价格
func CalcPrice(cfg ResNoble, endTime time.Time) uint32 {
now := time.Now()
price := cfg.RenewalPrice
if now.After(endTime.AddDate(0, 0, RENEWAL_LIMIT_DAY)) {
price = cfg.PurchasePrice
}
return price
}
package noble_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"time"
)
const (
SRC_APP = 1 // APP
SRC_OPERATION = 2 // 管理后台发放
SRC_H5 = 3 // H5页面
SRC_ACTIVITY = 4 // 活动奖励
RECHARGE_FIRST = 5 // 首次充值
)
type UserNobleLog struct {
mysql.Entity
SenderId uint64
ReceiverId uint64
Level uint16
Money uint32
SrcType uint16
OldEndTime time.Time
NewEndTime time.Time
}
func (ubl *UserNobleLog) Create(db *gorm.DB) error {
return db.Create(ubl).Error
}
package noble_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/resource/mysql"
"time"
)
......@@ -52,22 +52,6 @@ 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,
......@@ -93,3 +77,50 @@ func GetNobleLevel(db *gorm.DB, userId uint64) (uint16, error) {
return noble.Level, 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
}
func BatchGetActiveNoble(db *gorm.DB, userIds []uint64) (map[uint64]UserNoble, error) {
ub := UserNoble{}
records, err := ub.batchGet(db, userIds)
if err != nil {
return nil, err
}
result := make(map[uint64]UserNoble, 0)
for _, i := range userIds {
if len(records[i]) > 0 {
result[i] = records[i][0]
} else {
result[i] = UserNoble{}
}
}
return result, nil
}
// 查询用户未过期的贵族
func (ub *UserNoble) batchGet(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
}
......@@ -2,10 +2,10 @@ package model
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hilo-user/myerr"
"hilo-user/resource/mysql"
"time"
)
......
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/res_e"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
type ResCountry struct {
......
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type ResGift struct {
mysql.Entity
Name mysql.Str
IconUrl mysql.Str
SvagUrl mysql.Str
MusicUrl mysql.Str
Column uint16
DiamondNum mysql.Num
BeanNum mysql.Num
ReceiveDiamondNum mysql.Num
Second mysql.Num // obsolete
N mysql.Num
GroupBroadcast bool
Cp bool
Together bool
Status mysql.UserYesNo
GiftType mysql.Type
}
// 获取所有有效的礼物
func FindValidResGiftsMap(model *domain.Model) (map[mysql.ID]ResGift, error) {
res := make(map[mysql.ID]ResGift, 0)
rows := make([]ResGift, 0)
if err := model.DB().Model(ResGift{}).Where("status = ?", mysql.USER).Find(&rows).Error; err != nil {
return nil, err
}
for i, v := range rows {
res[v.ID] = rows[i]
}
return res, nil
}
// 获取礼物
func FindResGift(model *domain.Model, giftId mysql.ID) (*ResGift, error) {
res := new(ResGift)
if err := model.DB().Model(ResGift{}).Where("id = ?", giftId).First(res).Error; err != nil {
return nil, err
}
return res, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/myerr"
)
type ResHeadwear struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
PicUrl mysql.Str
EffectUrl mysql.Str
}
//矛盾,项目负责人(产品不接受 商品 同上架分开两个数据结构的模式),又在页面上要求头饰同价格在一起展示,修改。
//目前违背了,ResHeadwearDiamond 作为资源数据,不允许修改的特点。后果在于,对账错误。
type ResHeadwearDiamond struct {
mysql.Entity
*domain.Model `gorm:"-"`
ResHeadwearId mysql.ID
DiamondNum mysql.Num
Second mysql.Num
Status mysql.UserYesNo
}
func InitResHeadwearDiamond(model *domain.Model, resHeadwearId mysql.ID, diamondNum mysql.Num, second mysql.Num) *ResHeadwearDiamond {
return &ResHeadwearDiamond{
Model: model,
ResHeadwearId: resHeadwearId,
DiamondNum: diamondNum,
Second: second,
Status: mysql.NOUSER,
}
}
func GetResHeadwearDiamondByHeadwearIdOrNil(model *domain.Model, resHeadwearId mysql.ID) (*ResHeadwearDiamond, error) {
resHeadwearDiamond := ResHeadwearDiamond{}
if err := model.Db.Model(&ResHeadwearDiamond{}).Where(&ResHeadwearDiamond{
ResHeadwearId: resHeadwearId,
}).First(&resHeadwearDiamond).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
resHeadwearDiamond.Model = model
return &resHeadwearDiamond, nil
}
func (resHeadwearDiamond *ResHeadwearDiamond) SetDiamondNum(diamondNum uint32) *ResHeadwearDiamond {
resHeadwearDiamond.DiamondNum = diamondNum
return resHeadwearDiamond
}
func (resHeadwearDiamond *ResHeadwearDiamond) SetSecond(second uint32) *ResHeadwearDiamond {
resHeadwearDiamond.Second = second
return resHeadwearDiamond
}
//设置成未使用
func (resHeadwearDiamond *ResHeadwearDiamond) SetUser() *ResHeadwearDiamond {
resHeadwearDiamond.Status = mysql.USER
return resHeadwearDiamond
}
//设置成未使用
func (resHeadwearDiamond *ResHeadwearDiamond) SetNoUser() *ResHeadwearDiamond {
resHeadwearDiamond.Status = mysql.NOUSER
return resHeadwearDiamond
}
//id获取头饰,不存在则抛异常
func GetHeadwearById(model *domain.Model, id mysql.ID) (*ResHeadwear, error) {
resHeadwear := ResHeadwear{}
if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil {
return nil, myerr.WrapErr(err)
} else {
resHeadwear.Model = model
return &resHeadwear, nil
}
}
//初始化头饰,
func InitHeadwear(model *domain.Model, name string, picUrl string, effectUrl string) *ResHeadwear {
return &ResHeadwear{
Model: model,
Name: name,
PicUrl: picUrl,
EffectUrl: effectUrl,
}
}
//修改头饰
func (resHeadwear *ResHeadwear) EditName(name string) *ResHeadwear {
resHeadwear.Name = name
return resHeadwear
}
func (resHeadwear *ResHeadwear) EditPicUrl(picUrl string) *ResHeadwear {
resHeadwear.PicUrl = picUrl
return resHeadwear
}
func (resHeadwear *ResHeadwear) EditEffectUrl(effectUrl string) *ResHeadwear {
resHeadwear.EffectUrl = effectUrl
return resHeadwear
}
func CheckHeadwearValidById(model *domain.Model, id mysql.ID) (bool, error) {
resHeadwear := ResHeadwear{}
if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return false, nil
} else {
return false, myerr.WrapErr(err)
}
} else {
return true, nil
}
}
package res_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/res_e"
"hilo-user/resource/mysql"
)
type ResMedal struct {
......
package res_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/res_e"
"hilo-user/resource/mysql"
)
type ResNameplate struct {
......
package res_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/res_e"
"hilo-user/myerr"
"hilo-user/resource/mysql"
)
type ResMultiText struct {
......
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/res_m"
"hilo-user/myerr"
"strconv"
"time"
)
//用户头饰
type UserHeadwear struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
HeadwearId mysql.ID
EndTime time.Time
Using headwear_e.UserHeadwearUsing
}
//获取用户头饰,不存在则新建
func GetUserHeadwearOrInit(model *domain.Model, userId mysql.ID, headwearId mysql.ID) (*UserHeadwear, error) {
//检查headwearId是否存在/有效
if flag, err := res_m.CheckHeadwearValidById(model, headwearId); err != nil {
return nil, err
} else {
if flag == false {
return nil, myerr.NewSysError("headwearId: " + strconv.FormatUint(headwearId, 10) + " 无效")
}
}
userHeadwear := UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
HeadwearId: headwearId,
}).First(&userHeadwear).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &UserHeadwear{
Model: model,
UserId: userId,
HeadwearId: headwearId,
EndTime: time.Now(),
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userHeadwear.Model = model
return &userHeadwear, nil
}
//设置为使用中
func (userHeadwear *UserHeadwear) SetUsing() (*UserHeadwear, error) {
if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil {
return nil, err
}
userHeadwear.Using = headwear_e.YesUsing
return userHeadwear, nil
}
//增加结束时间
func (userHeadwear *UserHeadwear) AddEndTime(t headwear_e.UserHeadwearLogOrginType, second uint32, operateUserId mysql.ID) (*UserHeadwear, mysql.ID, error) {
logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, t, headwear_e.AddSecond, &second, nil, operateUserId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
//if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil {
// return nil, logId, err
//}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(second) * time.Second)
return userHeadwear, logId, nil
}
//删除
func (userHeadwear *UserHeadwear) MgrDel(mgrId mysql.ID) (*UserHeadwear, mysql.ID, error) {
logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, headwear_e.Mgr, headwear_e.Del, nil, nil, mgrId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
userHeadwear.SetDel()
return userHeadwear, logId, nil
}
//重置所有的座驾均为不使用状态
func resetAllUserHeadwearNoUsing(model *domain.Model, userId mysql.ID) error {
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
}).UpdateColumn("using", headwear_e.NoUsing).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
//用户装饰日志
type UserHeadwearLog struct {
mysql.Entity
UserId mysql.ID
OperateUserId mysql.ID
HeadwearId mysql.ID
OriginType headwear_e.UserHeadwearLogOrginType
Type headwear_e.UserHeadwearLogType
AddSecond *mysql.Num
UpdateEndTime *time.Time
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
func GetUserHeadwearUsing(model *domain.Model, userId mysql.ID) (*UserHeadwear, error) {
userHeadwear := UserHeadwear{}
if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{
UserId: userId,
}).Where("end_time > ?", time.Now()).Order("`using` desc, updated_time desc").First(&userHeadwear).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userHeadwear.Model = model
return &userHeadwear, nil
}
package user_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/match_e"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/resource/mysql"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
/**
......@@ -19,54 +16,15 @@ type MatchCharmUserScore struct {
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)
// 批量获取魅力等级
func MGetCharmGrade(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
res := make(map[mysql.ID]mysql.Num)
var charmUserScore []*MatchCharmUserScore
if err := model.Db.Model(&MatchCharmUserScore{}).Where("user_id in ?", userIds).Find(&charmUserScore).Error; err != nil {
return res, err
}
for _, r := range charmUserScore {
res[r.UserId] = r.Grade
}
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
return res, nil
}
package user_m
import (
"gorm.io/gorm"
"hilo-user/_const/enum/match_e"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/resource/mysql"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
/**
......@@ -19,52 +16,15 @@ type MatchWealthUserScore struct {
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)
// 批量获取财富等级
func MGetWealthGrade(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]mysql.Num, error) {
res := make(map[mysql.ID]mysql.Num)
var wealthUserScore []*MatchWealthUserScore
if err := model.Db.Model(&MatchWealthUserScore{}).Where("user_id in ?", userIds).Find(&wealthUserScore).Error; err != nil {
return res, err
}
for _, r := range wealthUserScore {
res[r.UserId] = r.Grade
}
return wealthUserScore.Grade, wealthUserScore.Score, nil
return res, 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"
"hilo-user/domain"
"hilo-user/domain/model/common"
"hilo-user/domain/model/res_m"
"hilo-user/resource/mysql"
"time"
)
......
package user_m
import (
"hilo-user/domain"
"hilo-user/resource/mysql"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"time"
)
......
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/property_e"
"hilo-user/myerr"
"time"
)
//用户道具
type UserProperty struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
PropertyId mysql.ID
EndTime time.Time
Using property_e.UserPropertyUsing
}
func GetUserPropertyOrInit(model *domain.Model, userId mysql.ID, propertyId mysql.ID) (*UserProperty, error) {
userProperty := UserProperty{}
if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{
UserId: userId,
PropertyId: propertyId,
}).First(&userProperty).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &UserProperty{
Model: model,
UserId: userId,
PropertyId: propertyId,
EndTime: time.Now(),
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
userProperty.Model = model
return &userProperty, nil
}
//设置为使用中
func (userProperty *UserProperty) SetUsing() (*UserProperty, error) {
if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil {
return nil, err
}
userProperty.Using = property_e.YesUsing
return userProperty, nil
}
//增加结束时间
func (userProperty *UserProperty) AddEndTime(t property_e.UserPropertyLogOrginType, second uint32, operateUserId mysql.ID) (*UserProperty, mysql.ID, error) {
logId, err := addUserPropertyLog(userProperty.Model, userProperty.UserId, userProperty.PropertyId, t, property_e.AddSecond, &second, nil, operateUserId)
if err != nil {
return nil, 0, myerr.WrapErr(err)
}
//if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil {
// return nil, logId, err
//}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(second) * time.Second)
return userProperty, logId, nil
}
//重置所有的座驾均为不使用状态
func ResetAllUserPropertyNoUsing(model *domain.Model, userId mysql.ID) error {
if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{
UserId: userId,
}).UpdateColumn("using", property_e.NoUsing).Error; err != nil {
return myerr.WrapErr(err)
}
return nil
}
//增加修改日志
func addUserPropertyLog(model *domain.Model, userId mysql.ID, propertyId mysql.ID, originType property_e.UserPropertyLogOrginType, t property_e.UserPropertyLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userPropertyLog := UserPropertyLog{
UserId: userId,
OperateUserId: operateUserId,
PropertyId: propertyId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userPropertyLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userPropertyLog.ID, nil
}
func RemoveUserProperty(model *domain.Model, userId mysql.ID, propertyId mysql.ID) error {
return model.Db.Where("user_id = ? AND property_id = ?", userId, propertyId).Delete(&UserProperty{}).Error
}
//用户道具日志
type UserPropertyLog struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
OperateUserId mysql.ID
PropertyId mysql.ID
OriginType property_e.UserPropertyLogOrginType
Type property_e.UserPropertyLogType
AddSecond *mysql.Num
UpdateEndTime *time.Time
}
\ No newline at end of file
package user_m
import "hilo-user/domain/model"
func (userHeadwear *UserHeadwear) Persistent() error {
return model.Persistent(userHeadwear.Db, userHeadwear)
}
func (userProperty *UserProperty) Persistent() error {
return model.Persistent(userProperty.Db, userProperty)
}
func (userPropertyLog *UserPropertyLog) Persistent() error {
return model.Persistent(userPropertyLog.Db, userPropertyLog)
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
)
//用户信息
......
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/resource/mysql"
"time"
)
......
package headwear_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/headwear_e"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"time"
)
type HeadwearService struct {
svc *domain.Service
}
func NewHeadwearService(myContext *mycontext.MyContext) *HeadwearService {
svc := domain.CreateService(myContext)
return &HeadwearService{svc}
}
// 下发头饰
func (s *HeadwearService) SendHeadwear(receiverUserId mysql.ID, headdressId mysql.ID, days int) error {
var model = domain.CreateModelContext(s.svc.MyContext)
// 头饰增加
receiveHeadwearDuration := uint32(days) * 3600 * 24
if headdressId <= 0 {
return bizerr.InvalidParameter
}
userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, headdressId)
if err != nil {
return err
}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second)
if err := userHeadwear.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if _, err = addUserHeadwearLog(model, receiverUserId, headdressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil {
model.Log.Error(err)
}
return err
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := user_m.UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
package noble_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/headwear_e"
"hilo-user/_const/enum/msg_e"
"hilo-user/_const/enum/property_e"
"hilo-user/domain/model/msg_m"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"strconv"
"time"
)
type NobleService struct {
svc *domain.Service
}
func NewNobleService(myContext *mycontext.MyContext) *NobleService {
svc := domain.CreateService(myContext)
return &NobleService{svc}
}
// 下发贵族
func (s *NobleService) SendNoble(receiverUserId mysql.ID, level uint16, days int) error {
model := domain.CreateModelContext(s.svc.MyContext)
if level <= 0 {
return bizerr.InvalidParameter
}
cfg, err := noble_m.GetConfigByLevel(model.Db, level)
if err != nil {
return err
}
if cfg.PurchasePrice <= 0 || cfg.RenewalPrice <= 0 {
return bizerr.InvalidParameter
}
n := noble_m.UserNoble{UserId: receiverUserId, Level: level}
records, err := n.FindAll(model.Db)
if err != nil {
return err
}
if len(records) > 1 {
// DB表结构决定了不可能发生
return bizerr.IncorrectState
}
if len(records) <= 0 {
// 新增贵族
endTime := time.Now().AddDate(0, 0, int(days))
n = noble_m.UserNoble{UserId: receiverUserId, Level: level, EndTime: endTime}
err = n.Create(model.Db)
if err != nil {
return err
}
nbl := noble_m.UserNobleLog{
SenderId: 0,
ReceiverId: receiverUserId,
Level: level,
Money: 0,
SrcType: noble_m.SRC_APP,
NewEndTime: endTime,
}
err = nbl.Create(model.Db)
if err != nil {
return err
}
} else {
// 延长贵族
n = records[0]
now := time.Now()
endTime := n.EndTime.AddDate(0, 0, int(days))
if now.After(n.EndTime) {
endTime = now.AddDate(0, 0, int(days))
}
nn := noble_m.UserNoble{
Entity: mysql.Entity{ID: n.ID, UpdatedTime: n.UpdatedTime},
}
af, err := nn.UpdateEndTime(model.Db, endTime)
if err != nil {
return err
}
if af <= 0 {
return bizerr.TransactionFailed
}
nbl := noble_m.UserNobleLog{
SenderId: 0,
ReceiverId: receiverUserId,
Level: level,
Money: 0,
SrcType: noble_m.SRC_APP,
OldEndTime: n.EndTime,
NewEndTime: endTime,
}
err = nbl.Create(model.Db)
if err != nil {
return err
}
}
// 头饰增加
receiveHeadwearDuration := uint32(days) * 3600 * 24
if cfg.HeaddressId != 0 {
userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, cfg.HeaddressId)
if err != nil {
return err
}
nowTime := time.Now()
if userHeadwear.EndTime.After(nowTime) {
nowTime = userHeadwear.EndTime
}
userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second)
if err := userHeadwear.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if _, err := addUserHeadwearLog(model, receiverUserId, cfg.HeaddressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil {
model.Log.Error(err)
}
}
// 增加座驾
receivePropertyDuration := uint32(days) * 3600 * 24
if cfg.RideId != 0 {
userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, cfg.RideId)
if err != nil {
return err
}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second)
if err := userProperty.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if err := (&user_m.UserPropertyLog{
Model: model,
UserId: receiverUserId,
PropertyId: cfg.RideId,
OriginType: property_e.ActivityBillboardTrigger,
Type: property_e.AddSecond,
AddSecond: &receivePropertyDuration,
UpdateEndTime: nil,
}).Persistent(); err != nil {
model.Log.Error(err)
}
}
// 推送
user, err := user_m.GetUser(model, receiverUserId)
if err != nil {
return err
}
nobleDuration := days * 3600 * 24
if err := msg_m.NewUserRecord(model, user.ID, msg_e.AddNoble, user.Nick, user.ID, "", strconv.Itoa(int(nobleDuration)/(24*3600)), "", "", "").Persistent(); err != nil {
return err
}
msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
return nil
}
//增加修改日志
func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) {
userHeadwearLog := user_m.UserHeadwearLog{
UserId: userId,
OperateUserId: operateUserId,
HeadwearId: headwearId,
OriginType: originType,
Type: t,
AddSecond: addSecond,
UpdateEndTime: UpdateEndTime,
}
if err := model.Db.Create(&userHeadwearLog).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return userHeadwearLog.ID, nil
}
package ride_s
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-user/_const/enum/property_e"
"hilo-user/domain/model/user_m"
"time"
)
type RideService struct {
svc *domain.Service
}
func NewRideService(myContext *mycontext.MyContext) *RideService {
svc := domain.CreateService(myContext)
return &RideService{svc}
}
// 下发座驾
func (s *RideService) SendRide(receiverUserId mysql.ID, rideId mysql.ID, days int) error {
model := domain.CreateModelContext(s.svc.MyContext)
// 增加座驾
receivePropertyDuration := uint32(days) * 3600 * 24
userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, rideId)
if err != nil {
return err
}
nowTime := time.Now()
if userProperty.EndTime.After(nowTime) {
nowTime = userProperty.EndTime
}
userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second)
if err := userProperty.Persistent(); err != nil {
return err
}
//日志错误,并不事务回调
if err := (&user_m.UserPropertyLog{
Model: model,
UserId: receiverUserId,
PropertyId: rideId,
OriginType: property_e.ActivityBillboardTrigger,
Type: property_e.AddSecond,
AddSecond: &receivePropertyDuration,
UpdateEndTime: nil,
}).Persistent(); err != nil {
model.Log.Error(err)
}
return nil
}
package service
import (
"hilo-user/domain"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"hilo-user/resource/redisCli"
"runtime/debug"
)
type Service struct {
*domain.CtxAndDb
}
func (service *Service) getMyContext() *mycontext.MyContext {
return service.MyContext
}
/**
* 创建服务
* @param
* @return
**/
func CreateService(myContext *mycontext.MyContext) *Service {
if myContext == nil {
return &Service{CtxAndDb: &domain.CtxAndDb{
Db: mysql.Db,
MyContext: mycontext.CreateMyContext(nil),
Redis: redisCli.GetRedis(),
}}
} else {
return &Service{CtxAndDb: &domain.CtxAndDb{
Db: mysql.Db,
MyContext: myContext,
Redis: redisCli.GetRedis(),
}}
}
}
//事务钩子回调,遇到错误,异常则回调,写service都需要钩子回调
func (service *Service) Transactional(callback func() error) error {
//异常回调
defer func() {
if err := recover(); err != nil {
service.Log.Errorf("doTransactional SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
service.Db.Rollback()
//为了防止给controller层造成数据错误,继续抛恐慌
panic(err)
}
}()
service.CtxAndDb.Db = mysql.Db.Begin()
err := callback()
if err != nil {
service.Db.Rollback()
return err
}
//提交
return service.Db.Commit().Error
}
......@@ -2,6 +2,8 @@ module hilo-user
go 1.17
replace git.hilo.cn/hilo-common => ../hilo-common
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/dgrijalva/jwt-go v3.2.0+incompatible
......@@ -25,9 +27,11 @@ require (
)
require (
git.hilo.cn/hilo-common v0.0.0-00010101000000-000000000000 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
......@@ -40,15 +44,17 @@ require (
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/serf v0.9.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
......@@ -62,8 +68,9 @@ require (
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
......@@ -8,6 +8,8 @@ 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/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/aliyun/alibaba-cloud-sdk-go v1.61.1274 h1:u48e7I7h/BY5uDP8xiIFNaUkdTVk7hjj/Sucg8FrxNU=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
......@@ -67,13 +69,18 @@ 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-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
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.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hashicorp/consul/api v1.7.0 h1:tGs8Oep67r8CcA2Ycmb/8BLBcJ70St44mF2X10a/qPg=
github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg=
github.com/hashicorp/consul/sdk v0.6.0 h1:FfhMEkwvQl57CildXJyGHnwGGM4HMODGyfjGwNM1Vdw=
......@@ -99,6 +106,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
......@@ -114,6 +123,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg=
......@@ -122,6 +133,7 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
......@@ -193,12 +205,15 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
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/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
......@@ -254,24 +269,32 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 h1:xFbv3LvlvQAmbNJFCBKRv1Ccvnh9FVsW0FX2kTWWowE=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/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=
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/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
......@@ -280,6 +303,8 @@ gopkg.in/yaml.v2 v2.2.2/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/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
......
......@@ -2,18 +2,20 @@ package main
import (
"fmt"
"hilo-user/resource/consul"
"git.hilo.cn/hilo-common/resource/consul"
"hilo-user/route"
)
const (
PORT = 9040
RegisterName = "hiloUser"
RegisterTag = "用户中心"
)
func main() {
//cron.Init() // 开启定时任务
//event_s.EventInit() // 注册事件(内部事件+mysql拟kafka)
r := route.InitRouter() // 注册路由
consul.RegisterToConsul(PORT) // 服务注册
consul.RegisterToConsul(PORT, RegisterName, RegisterTag) // 服务注册
r.Run(fmt.Sprintf(":%d", PORT)) // 启动服务
}
package mycontext
import (
"context"
uuid "github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
"hilo-user/_const"
"hilo-user/mylogrus"
"strconv"
"strings"
)
/**
* 主要是完成日志打印
* @param
* @return
**/
type MyContext struct {
context.Context
Log *logrus.Entry
Cxt map[string]interface{}
}
func CreateMyContextWith(traceId interface{}) *MyContext {
cxt := map[string]interface{}{}
cxt[_const.TRACEID] = traceId
return CreateMyContext(cxt)
}
func CreateMyContext(ctx map[string]interface{}) *MyContext {
var traceId string
if traceIdTemp, ok := ctx[_const.TRACEID]; ok {
traceId, ok = traceIdTemp.(string)
} else {
traceId = strings.Replace(uuid.NewV4().String(), "-", "", -1)
}
var userId string
if userIdTemp, ok := ctx[_const.USERID]; ok {
userId = strconv.FormatUint(userIdTemp.(uint64), 10)
}
var deviceTypeStr string
if deviceTypeTemp, ok := ctx[_const.DEVICETYPE]; ok {
deviceTypeStr, ok = deviceTypeTemp.(string)
}
var sAppVersion string
if appVersionTmp, ok := ctx[_const.APP_VERSION]; ok {
sAppVersion, ok = appVersionTmp.(string)
}
var url string
if urlTmp, ok := ctx[_const.URL]; ok {
url, ok = urlTmp.(string)
}
var method string
if methodTmp, ok := ctx[_const.METHOD]; ok {
method, ok = methodTmp.(string)
}
_ctx := context.WithValue(context.Background(), "traceId", traceId)
_ctx = context.WithValue(_ctx, "userId", userId)
return &MyContext{
Context: _ctx,
Log: CreateContextLog(userId, traceId, deviceTypeStr, sAppVersion, url, method),
Cxt: ctx,
}
}
/**
* 创建上下文的日志
**/
func CreateContextLog(userId string, traceId string, deviceType string, deviceVersion string, url string, method string) *logrus.Entry {
return mylogrus.MyLog.WithFields(logrus.Fields{
_const.USERID: userId,
_const.TRACEID: traceId,
_const.DEVICETYPE: deviceType,
_const.APP_VERSION: deviceVersion,
_const.URL: url,
_const.METHOD: method,
})
}
......@@ -11,6 +11,8 @@ var (
CodeNoExist = myerr.NewBusinessCode(1005, "code no exist", myerr.BusinessData{})
ParaMissing = myerr.NewBusinessCode(1006, "parameter missing", myerr.BusinessData{})
InvalidParameter = myerr.NewBusinessCode(1009, "Invalid parameter", myerr.BusinessData{})
IncorrectState = myerr.NewBusinessCode(1013, "Incorrect state", myerr.BusinessData{})
TransactionFailed = myerr.NewBusinessCode(1014, "Transaction failed", myerr.BusinessData{})
ReqTooFrequent = myerr.NewBusinessCode(1018, "Requests are too frequent", myerr.BusinessData{})
// 钻石
......
......@@ -2,8 +2,8 @@ package myerr
import (
"fmt"
"git.hilo.cn/hilo-common/mylogrus"
"github.com/pkg/errors"
"hilo-user/mylogrus"
"strconv"
)
......
package mylogrus
import (
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"io"
"os"
"path/filepath"
"time"
)
const logDir = "/var/log/hilo/"
var filenamePrefix string
var MyLog = logrus.New()
func Info(v interface{}) {
MyLog.Info("")
}
func init() {
filenamePrefix = logDir + filepath.Base(os.Args[0]) + "."
// stderr日志重定向
MyLog.SetOutput(os.Stdout)
RewriteStderrFile()
MyLog.SetFormatter(&logrus.TextFormatter{
ForceQuote: false,
DisableQuote: true,
TimestampFormat: "2006-01-02 15:04:05.000",
FullTimestamp: true,
})
hook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: getLevelWrite(logrus.DebugLevel),
logrus.InfoLevel: getLevelWrite(logrus.InfoLevel),
logrus.WarnLevel: getLevelWrite(logrus.WarnLevel),
logrus.ErrorLevel: getLevelWrite(logrus.ErrorLevel),
logrus.FatalLevel: getLevelWrite(logrus.FatalLevel),
logrus.PanicLevel: getLevelWrite(logrus.PanicLevel),
}, &logrus.TextFormatter{ForceQuote: false, DisableQuote: true, TimestampFormat: time.RFC3339Nano})
MyLog.AddHook(hook)
MyLog.SetLevel(logrus.InfoLevel)
MyLog.SetReportCaller(true)
}
func GetInfoLog() io.Writer {
return getLevelWrite(logrus.InfoLevel)
}
func getLevelWrite(level logrus.Level) io.Writer {
var name string
switch level {
case logrus.DebugLevel:
name = "debug.log"
case logrus.InfoLevel:
name = "info.log"
case logrus.WarnLevel:
name = "warn.log"
case logrus.ErrorLevel:
name = "error.log"
case logrus.FatalLevel:
name = "fatal.log"
case logrus.PanicLevel:
name = "panic.log"
}
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
func GetSqlLog() io.Writer {
var name string = "sql.log"
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
//go:build !windows
// +build !windows
package mylogrus
import (
"fmt"
"os"
"path/filepath"
"runtime"
"syscall"
"time"
)
var stdErrFileHandler *os.File
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
//if runtime.GOOS == "darwin" { // mac本地调试
// filename = "./log/hilo/" + filepath.Base(os.Args[0]) + ".stderr.log"
//}
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Println(err)
return
}
stdErrFileHandler = file //把文件句柄保存到全局变量,避免被GC回收
if err = syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
fmt.Println(err)
return
}
// 内存回收前关闭文件描述符
runtime.SetFinalizer(stdErrFileHandler, func(fd *os.File) {
fd.Close()
})
return
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
//go:build windows
// +build windows
package mylogrus
import (
"os"
"path/filepath"
"time"
)
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
MyLog.Errorf("stderr log in:%v,err:%v", file, err)
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
syntax = "proto3";
package biz;
option go_package = "protocol/biz";
/* id = 1 */
message BizMessage {
uint32 type = 2;
string payLoad = 3;
}
/* id = 2 */
message BizMessageRsp {
uint32 status = 1;
}
service Transmitter {
rpc process(BizMessage) returns (BizMessageRsp) {}
}
\ No newline at end of file
syntax = "proto3";
package userCenter;
option go_package = "protocol/userCenter";
/* id = 1 */
message RouteMessage {
uint64 uid = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 2 */
message RouteMessageRsp {
uint32 status = 1;
}
/* id = 3 */
message LoginMessage {
string proxyAddr = 1; // userProxy的地址:ip:port
string token = 2;
string clientAddr = 3; // 客户端地址(websocket):ip:port
}
/* id = 4 */
message LoginMessageRsp {
uint32 status = 1;
uint64 uid = 2;
}
/* id = 5 */
message LogoutMessage {
string clientAddr = 1; // 客户端地址(websocket):ip:port
uint64 uid = 2;
}
/* id = 6 */
message LogoutMessageRsp {
uint32 status = 1;
}
/* id = 7 */
message MulticastMessage {
repeated uint64 uids = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 8 */
message MulticastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 9 */
message KickMessage {
uint64 uid = 1;
string addr = 2;
}
/* id = 10 */
message KickMessageRsp {
uint32 status = 1;
}
/* id = 11 */
message BroadcastMessage {
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 12 */
message BroadcastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 13 */
message BizMessage {
uint64 uid = 1;
uint32 msgType = 2;
string payLoad = 3;
}
/* id = 14 */
message BizMessageRsp {
uint32 status = 1;
}
service Router {
rpc route(RouteMessage) returns (RouteMessageRsp) {}
rpc kickUser(KickMessage) returns (KickMessageRsp) {}
}
service User {
rpc login(LoginMessage) returns (LoginMessageRsp) {}
rpc logout(LogoutMessage) returns (LogoutMessageRsp) {}
rpc multicast(MulticastMessage) returns (MulticastMessageRsp) {}
rpc broadcast(BroadcastMessage) returns (BroadcastMessageRsp) {}
rpc transmit(BizMessage) returns (BizMessageRsp) {}
}
\ No newline at end of file
syntax = "proto3";
package userProxy;
option go_package = "protocol/userProxy";
/* id = 1 登录*/
message Login {
string token = 1;
}
/* id = 2 登录的回应 */
message LoginRsp {
uint32 status = 1;
}
/* id = 3 客户端心跳 */
message HeartBeat {
string externalUid = 1;
}
/* id = 4 客户端心跳的回应 */
message HeartBeatRsp {
uint32 status = 1;
}
/* id = 7 客户端上行消息 */
message BizRequest {
uint32 type = 1;
string payLoad = 2;
}
/* id = 8 客户端上行消息的应答 */
message BizResponse {
uint32 status = 1;
}
/* id == 100 匹配结果通知 waitDuration:开始/下一个时间 matchUniqueId:匹配一对的唯一标识码, status:是否是落单 singleWaitTimeInSec:单方等待连接最长时间 dualWaitTimeInSec:双方连接中最长时间*/
message MatchSuccess {
string localUserId = 1;
string remoteUserId = 2;
uint32 waitDuration = 3;
string matchUniqueId = 4;
bool status = 5;
uint32 singleWaitTimeInSec = 6;
uint32 dualWaitTimeInSec = 7;
}
/* id == 101 匹配后用户选择结果通知, failType: 只有status=2 才有值,其它为0,failType=1:等待时间到了,拒绝 failType=2:主动拒绝 */
message MatchConfirm {
uint32 status = 1;
string channelId = 2;
string token = 3;
string localUserId = 4;
string remoteUserId = 5;
uint32 remoteAgoraId = 6;
uint32 callDuration = 7;
uint32 localAgoraId = 8;
uint32 diamondBalance = 9;
string matchUniqueId = 10;
uint32 failType = 11;
}
/* id == 102 视频通话准备 */
message CallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 103 礼物加时 */
message AddTimeGift {
uint32 giftId = 1;
string token = 2;
uint32 duration = 3;
uint64 endTimestamp = 4;
string channelId = 5;
bool isSender = 6;
uint32 giftNum = 7;
string iconUrl = 8;
string svgaUrl = 9;
string senderAvatar = 10;
string receiverAvatar = 11;
}
/* id == 104 免费加时 */
message AddTimeFree {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
}
/* id == 105 退出 */
message ConnectsQuit {
uint64 from_user_id = 1;
}
/* id == 106 连接状态 */
message ConnectStatus {
uint64 from_user_id = 1;
float user_diamonds = 2;
bool diamonds_enough = 3;
}
/* id == 107 ??? */
message ConnectsCall {
uint64 from_user_id = 1;
string rong_room_name = 2;
bool is_join = 3;
}
/* id == 108 */
message ConnectCommon {
string rong_room_name = 1;
uint64 from_user_id = 2;
string extra = 3;
string message = 4;
}
/* id == 109 召回授权弹框 */
message RecallWindow {
}
/* id == 110 视频发送 status:(1:接收到邀请, 2:接收到对方同意, 3:双方拒绝(还没接通), 4:对方挂断(接通后)diamondBalance 只有status=2,才出现)*/
message Video {
string videoUniqueId = 1;
string channelId = 2;
uint32 localAgoraId = 3;
uint32 remoteAgoraId = 4;
string agoraToken = 5;
string sendUserId = 6;
string receiveUserId = 7;
uint32 status = 8;
uint32 diamondBalance = 9;
}
/* id == 111 视频通话准备 */
message VideoCallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 112 互相喜欢 */
message LikeEach {
string remoteUserId = 1;
}
/* id == 113 喜欢我 */
message LikeMe {
string remoteUserId = 1;
string remoteNick = 2;
string channelId = 3;
}
/* id == 114 日常进入app,获取钻石 */
message DailyInAppDiamond {
uint32 diamondNum = 1;
}
/* id == 115 横幅 */
message GlobalGiftBanner {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
string sendUserCode = 7;
string sendUserAvatar = 8;
string sendUserNick = 9;
string receiveUserNick = 10;
string giftPicUrl = 11;
}
/* id == 116 横幅的回应,用来测量RTT */
message GlobalGiftBannerRsp {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
}
/*id==117 幸运转盘通知,客户端重新拉取查询, type:客户端不用理*/
message LuckyWheel {
string groupId = 1;
uint32 type = 2;
}
/* id == 118 幸运转盘获胜者全服广播 */
message LuckyWheelBanner {
uint32 diamondNum = 1;
string sendUserId = 2;
string groupId = 3;
string nick = 4;
string code = 5;
string avatar = 6;
}
/* id == 119 幸运转盘钻石变化 */
message LuckyWheelDiamondChange {
string groupId = 1;
}
/* id == 120 服务器配置变更 */
message ConfigChange {
uint32 type = 1;
}
/* id == 121 全局火箭横幅 */
message GlobalRocketNotice {
string groupId = 1;
string period = 2;
uint32 round = 3;
uint32 stage = 4;
string topUserIcon = 5;
string nick = 6;
string code = 7;
string avatar = 8;
}
/* id == 122 群发功能弹窗 */
message GroupSendNotice {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string text = 5;
string groupName = 6;
string groupCode = 7;
string groupAvatar = 8;
uint32 userInNum = 9; // 最近进入房间的人数
string groupId = 10;
}
/* id == 123 全球消息 */
message GlobalBroadcast {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string senderNick = 5;
string msg = 6;
string groupId = 7;
uint32 senderNobleLevel = 8;
}
/* id == 124 全球消息 */
message MicTaskFinish {
string userId = 1;
uint32 diamond = 2;
}
/* id == 125 水果机开奖通知 */
message FruitMachine {
string date = 1;
uint32 round = 2;
}
/* id == 126 贵族变化 */
message NobleChange {
}
/* id == 127 加入群组成功 */
message JoinGroup {
string groupId = 1;
string externalId = 2;
}
/* id == 128 1对1视频1分钟加时成功 */
message VideoTimeMinuteSuccess {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
string videoUniqueId = 6;
bool isSend = 7;
uint32 sendRemainDiamond = 8;
}
/* id == 129 1对1视频1分钟加时询问检查 */
message VideoTimeMinuteCheck {
string videoUniqueId = 1;
uint32 diamond = 2;
string uuid = 3;
}
/* id == 130 1对1视频,错过 */
message VideoMiss {
uint32 totalNum = 1;
}
/* id == 131 进房,群组活动信息 */
message GroupActivity {
string ActivityId = 1;// id
uint64 StartAt = 2; // 开始时间戳,东八区时间戳
uint64 EndAt = 3; // 结束时间戳,东八区时间戳
string Banner = 4; // banner url
int32 AcType = 5; // 类型1.游戏2.比赛3.排队4.诗歌
string Theme = 6; // 活动主题
int32 PersonNum = 7; // 订阅人数
bool IsSubscribe = 8; // 我是否订阅该活动
string GroupId = 9; // 群id
}
\ No newline at end of file
syntax = "proto3";
package video;
option go_package = "protocol/video";
/* id = 1 视频加时 */
message VideoMinuteConfirm {
string videoUid = 1;
string externalId = 2;
}
/* id = 2 视频加时的应答 */
message VideoMinuteConfirmRsp {
uint32 status = 1;
}
package jwt
import (
"git.hilo.cn/hilo-common/resource/config"
"github.com/dgrijalva/jwt-go"
"hilo-user/myerr"
"hilo-user/resource/config"
"time"
)
......
package req
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/domain"
"hilo-user/domain/cache/user_c"
"hilo-user/domain/model/res_m"
"hilo-user/mycontext"
"hilo-user/myerr/bizerr"
"hilo-user/resource/mysql"
)
func GetUserId(c *gin.Context) (mysql.ID, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
return userId, nil
}
......@@ -21,10 +20,10 @@ func GetUserId(c *gin.Context) (mysql.ID, error) {
// 获取userId和externalId
func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
externalId, ok := c.Get(_const.EXTERNAL_ID)
externalId, ok := c.Get(mycontext.EXTERNAL_ID)
if ok {
return userId, externalId.(string), nil
} else {
......@@ -40,11 +39,11 @@ func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID
// 获取userId和ExtId和code
func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
userCode, ok1 := c.Get(_const.CODE)
externalId, ok2 := c.Get(_const.EXTERNAL_ID)
userCode, ok1 := c.Get(mycontext.CODE)
externalId, ok2 := c.Get(mycontext.EXTERNAL_ID)
if ok1 && ok2 {
return userId, externalId.(string), userCode.(string), nil
} else {
......@@ -60,10 +59,10 @@ func GetUserIdExtIdCode(c *gin.Context, myContext *mycontext.MyContext) (mysql.I
// 获取userId和LANGUAGE
func GetUserIdLang(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[_const.USERID]; ok {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
userId := userIdStr.(uint64)
lang, ok := c.Get(_const.LANGUAGE)
lang, ok := c.Get(mycontext.LANGUAGE)
if ok {
return userId, lang.(string), nil
} else {
......
package config
import (
"github.com/joho/godotenv"
"gopkg.in/ini.v1"
"hilo-user/mylogrus"
"os"
"runtime"
"strconv"
)
// 数据库的配置
type MysqlConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
type MysqlCodeConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
// redis配置
type RedisConfig struct {
REDIS_HOST string
REDIS_PASSWORD string
}
// jwt
type JwtConfig struct {
SECRET string
ISSUER_API string
ISSUER_MGR string
EXPIRE string
}
// jwt
type GameJwtConfig struct {
SECRET string
ISSUER_CLIENT string
ISSUER_SERVER string
EXPIRE string
}
// oss
type OssConfig struct {
OSS_ACCESS_KEY_ID string
OSS_ACCESS_KEY_SECRET string
OSS_ROLE_ARN string
OSS_END_POINT string
OSS_BUCKET string
OSS_CDN string
OSS_EXPIRED_TIME uint
OSS_STS_POINT string
OSS_STS string
OSS_STS_AES string
}
// aws
type AwsConfig struct {
AWS_BUCKET string
AWS_CDN string
AWS_DIR string
CONFIDENCE float32
}
// APP
type AppConfig struct {
BIZ_SECRET string
WEB_SECRET string
OPERATION_SECRET string
SUPERUSER string
OFFICIAL_GROUP string
MINIMAL_VERSION_ANDROID int
MINIMAL_VERSION_IOS int
MODERATE string
}
// googlePay 配置信息
type GooglePayConfig struct {
JsonKey []byte
}
// 融云
type RongyunConfig struct {
RONG_CLOUD_APP_KEY string
RONG_CLOUD_APP_SECRET string
RONG_CLOUD_URL string
}
// 腾讯云
type TencentyunConfig struct {
TENCENTYUN_APP_ID int
TENCENTYUN_KEY string
TX_OVERSEA_APP_ID int
TX_OVERSEA_KEY string
}
// emas
type EmasConfig struct {
ANDROID_APP_KEY string
ANDROID_APP_SECRET string
REGION_ID string
ACCESS_KEY_ID string
ACCESS_KEY_SECRET string
IOS_APP_KEY string
IOS_APP_SECRET string
APNS string
}
// 声网
type AgoraConfig struct {
APP_ID string
APP_CERTIFICATE string
CUSTOMER_KEY string
CUSTOMER_SECRET string
}
// 匹配的配置
type MatchConfig struct {
//一开始匹配的默认时长(单位:秒)
MATCH_FREE_TIME int
//一开始匹配的默认时长(单位:秒)VIP
MATCH_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
MATCH_ADD_TIME_FREE int
//匹配的声网的延迟加时(单位:秒)
MATCH_AGORA_TIME int
//匹配周期(单位:秒)
MATCH_CYCLE int
//过期时间(单位:秒),用户redisCache时间
MATCH_USER_EXPIRES int
//pb match_success中, wait_duration 开始/下一个时间(单位:秒)
MATCH_SUCCESS_WAIT_DURATION uint32
//pb match_success中, single_wait_time_in_sec 单方等待连接最长时间(单位:秒)
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC uint32
//pb match_success中, dual_wait_time_in_sec 双方连接中最长时间(单位:秒)
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC uint32
}
// 在线
type OnlineConfig struct {
//在线周期
ONLINE_CYCLE int
//在线过期时间
ONLINE_USER_EXPIRES int
}
// 1对1视频
type VideoConfig struct {
VIDEO_DAILY_FREE_NUM int
//一开始匹配的默认时长(单位:秒)
VIDEO_FREE_TIME int
//一开始匹配的默认时长(单位:秒),vip
VIDEO_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
VIDEO_ADD_TIME_FREE int
//声网的延迟加时(单位:秒)
VIDEO_AGORA_TIME int
//1分钟视频,普通用户价格
VIDEO_MINUTE_NORMAL int
//1分钟视频,公会用户价格
VIDEO_MINUTE_UNION int
}
// 会话
type SessionConfig struct {
SESSION_DAILY_FREE_NUM int
GUILD_USER_HELLO_DAY int
}
type BeanConfig struct {
DIAMOND_BEAN_RATE int
}
type H5Config struct {
USER_LEVEL string
GROUP_SUPPORT string
LUCKY_WHEEL string
WEEKLY_STAR string
WEEKLY_CP string
COUNTRY_STAR string
NOBLE_BUY_IOS string
GUILD_DATA_URL string
MGR_GUILD_DATA_URL string
RANKING_PINK_DIAMOND_URL string
}
type GroupImConfig struct {
MSG_SORT_EXPIRE int
MSG_SORT_SNAP int
MSG_PARALLEL_SIZE int
}
type GradeConfig struct {
//魅力速度
CHARM_SPEED_VIP int
//活跃
ACTITY_SPEED_VIP int
//财富
WEALTH_SPEED_VIP int
}
type LikeConfig struct {
//喜欢人数
I_LIKE_NUM int
//喜欢人数VIP
I_LIKE_NUM_VIP int
//喜欢人数贵族
I_LIKE_NUM_NOBLE int
}
type ApplePayConfig struct {
PASSWORD string
}
type RegisterConfig struct {
IMEI_TOTAL int
IMEI_OAUTH int
ACCOUNT_IP int
ACCOUNT_IP_DURATION int
}
type BannerConfig struct {
GIFT_BANNER_LEVEL1 int
GIFT_BANNER_LEVEL2 int
GIFT_BANNER_LEVEL3 int
}
type DiamondConfig struct {
DAILY_LOGIN_IMEI_LIMIT int
DAILY_LOGIN_IP_LIMIT int
PRIVATE_GIFT_RETURN int
NEW_USER_INVITE_AWARD uint32
}
type LuckWheelConfig struct {
MINIMAL_PARTICIPANT int // 轮盘开始最少需要的参与人数
WAIT_TIMELONG int // 等待轮盘开始的时长(分钟)
WINNER_DIAMOND_BANNER int //全服广播钻石门槛
}
// 自定义主题
type GroupCustomThemeConfig struct {
PIC_LIMIT int //图片数量
DAY int //有效天数
}
type GiftConfig struct {
WALL_DIAMOND int //上礼物墙,礼物钻石金额
}
type DailyConfig struct {
LOGIN_COMMON int
LOGIN_VIP int
}
type FruitTycoonConfig struct {
BIG_WINNER_THRESDHOLD uint
BIG_WINNER_LOW uint
BIG_WINNER_HIGH uint
POOL_RATIO uint32
WATERMELON_RATIO uint32
}
type ActivityConfig struct {
COUNTRY_STAR_POOL_RATIO uint32
COUNTRY_STAR_ORDINARY_RATIO uint32
}
type CheckoutConfig struct {
URL string
AUTHORIZATION string
H5 string
HILO_SECRET_KEY string
}
type RiskControlConfig struct {
USER_QPS_LIMIT int64
USER_URL_QPS_LIMIT int64
}
type PayerMaxConfig struct {
URL string
KEY string
MERCHANT_ID string
BIZ_TYPE string
VERSION string
FRONT_CALLBACK_URL string
SHOW_RESULT string
EXPIRE_TIME string
LANGUAGE string
}
type SudConfig struct {
API_LIST string
}
type URLConfig struct {
BIZ_HTTP string
}
const (
LOCAL string = "local"
DEBUG string = "debug"
RELEASE string = "release"
)
var mysqlConfigData MysqlConfig
var mysqlCodeConfigData MysqlCodeConfig
var redisConfigData RedisConfig
var jwtConfigData JwtConfig
var userJwtConfigData GameJwtConfig
var appConfigData AppConfig
var ossConfigData OssConfig
var awsConfigData AwsConfig
var googlePayData GooglePayConfig
var rongyunData RongyunConfig
var tencentyunData TencentyunConfig
var emasData EmasConfig
var agora AgoraConfig
var matchData MatchConfig
var onlineData OnlineConfig
var sessionData SessionConfig
var videoData VideoConfig
var beanData BeanConfig
var h5Data H5Config
var groupImData GroupImConfig
var gradeData GradeConfig
var likeData LikeConfig
var applePayData ApplePayConfig
var registerData RegisterConfig
var bannerConfig BannerConfig
var diamondConfig DiamondConfig
var luckyWheelConfig LuckWheelConfig
var groupCustomThemeConfig GroupCustomThemeConfig
var giftConfig GiftConfig
var dailyConfig DailyConfig
var fruitTycoonConfig FruitTycoonConfig
var activityConfig ActivityConfig
var checkoutConfig CheckoutConfig
var riskControl RiskControlConfig
var payerMaxConfig PayerMaxConfig
var mode string
var master bool
var sudConfig SudConfig
var urlConfig URLConfig
func GetConfigMysql() MysqlConfig {
return mysqlConfigData
}
func GetConfigMysqlCode() MysqlCodeConfig {
return mysqlCodeConfigData
}
func GetConfigRedis() RedisConfig {
return redisConfigData
}
func GetConfigJWT() JwtConfig {
return jwtConfigData
}
func GetConfigGameJWT() GameJwtConfig {
return userJwtConfigData
}
func GetConfigApp() AppConfig {
return appConfigData
}
func GetConfigOss() OssConfig {
return ossConfigData
}
func GetConfigAws() AwsConfig {
return awsConfigData
}
func GetConfigGooglePay() GooglePayConfig {
return googlePayData
}
func GetMode() string {
return mode
}
func AppIsRelease() bool {
return GetMode() == RELEASE
}
func AppIsLocal() bool {
return GetMode() == LOCAL
}
func IsMaster() bool {
return master
}
func GetOssCDN() string {
return ossConfigData.OSS_CDN
}
func GetRongyunAppKey() string {
return rongyunData.RONG_CLOUD_APP_KEY
}
func GetRongyunAppSecret() string {
return rongyunData.RONG_CLOUD_APP_SECRET
}
func GetRongyunUrl() string {
return rongyunData.RONG_CLOUD_URL
}
func GetTencentyunAppId() int {
return tencentyunData.TENCENTYUN_APP_ID
}
func GetTencentyunKey() string {
return tencentyunData.TENCENTYUN_KEY
}
func GetTxOverSeaAppId() int {
return tencentyunData.TX_OVERSEA_APP_ID
}
func GetTxOverSeaAppKey() string {
return tencentyunData.TX_OVERSEA_KEY
}
func GetEmasRegionId() string {
return emasData.REGION_ID
}
func GetEmasAccessKeyId() string {
return emasData.ACCESS_KEY_ID
}
func GetEmasAccessKeySecret() string {
return emasData.ACCESS_KEY_SECRET
}
func GetEmasAndroidAppKey() string {
return emasData.ANDROID_APP_KEY
}
func GetEmasIosAppKey() string {
return emasData.IOS_APP_KEY
}
func GetEmasApns() string {
return emasData.APNS
}
func GetAgoraAppId() string {
return agora.APP_ID
}
func GetAgoraAppCertificate() string {
return agora.APP_CERTIFICATE
}
func GetAgoraCustomerKey() string {
return agora.CUSTOMER_KEY
}
func GetAgoraCustomerSecret() string {
return agora.CUSTOMER_SECRET
}
func GetMatchConfig() *MatchConfig {
return &matchData
}
func GetOnlineConfig() *OnlineConfig {
return &onlineData
}
func GetSessionConfig() SessionConfig {
return sessionData
}
func GetVideoConfig() VideoConfig {
return videoData
}
func GetBeanConfig() BeanConfig {
return beanData
}
func GetH5Config() H5Config {
return h5Data
}
func GetGroupImConfig() GroupImConfig {
return groupImData
}
func GetGradeConfig() GradeConfig {
return gradeData
}
func GetLikeConfig() LikeConfig {
return likeData
}
func GetApplePayConfig() ApplePayConfig {
return applePayData
}
func GetRegisterConfig() RegisterConfig {
return registerData
}
func GetBannerConfig() BannerConfig {
return bannerConfig
}
func GetDiamondConfig() DiamondConfig {
return diamondConfig
}
func GetLuckyWheelConfig() LuckWheelConfig {
return luckyWheelConfig
}
func GetGroupCustomThemeConfig() GroupCustomThemeConfig {
return groupCustomThemeConfig
}
func GetGiftConfig() GiftConfig {
return giftConfig
}
func GetDailyConfig() DailyConfig {
return dailyConfig
}
func GetFruitTycoonConfig() FruitTycoonConfig {
return fruitTycoonConfig
}
func GetActivityConfig() ActivityConfig {
return activityConfig
}
func GetCheckoutConfig() CheckoutConfig {
return checkoutConfig
}
func GetRiskControlConfig() RiskControlConfig {
return riskControl
}
func GetPayerMaxConfig() PayerMaxConfig {
return payerMaxConfig
}
func GetSudConfig() SudConfig {
return sudConfig
}
func GetUrlConfig() URLConfig {
return urlConfig
}
func init() {
str, _ := os.Getwd()
mylogrus.MyLog.Info(str)
envDir := ".env"
//加载环境变量
if err := godotenv.Load(envDir); err != nil {
mylogrus.MyLog.Fatalf("Error loading .env err:%v", err)
}
//获取环境变量
mode = os.Getenv("MODE")
var err error
master, _ = strconv.ParseBool(os.Getenv("MASTER"))
mylogrus.MyLog.Infof("My role is %t", master)
iniDir := mode + ".ini"
if runtime.GOOS == "darwin" { // mac本地调试
iniDir = "/var/log/hilo/" + iniDir
}
//根据环境变量获取具体的配置,实现多环境配置
//var conf *ini.File
conf, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, iniDir)
if err != nil {
mylogrus.MyLog.Fatal(err)
}
//加载mysql的配置
if err := conf.Section("DATABASE").MapTo(&mysqlConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DATABASECODE").MapTo(&mysqlCodeConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("REDIS").MapTo(&redisConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("JWT").MapTo(&jwtConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GAMEJWT").MapTo(&userJwtConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("APP").MapTo(&appConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
mylogrus.MyLog.Infof("APP: %+v", appConfigData)
}
if err := conf.Section("OSS").MapTo(&ossConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("AWS").MapTo(&awsConfigData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if awsConfigData.CONFIDENCE <= 50 {
awsConfigData.CONFIDENCE = 80
}
mylogrus.MyLog.Infof("AWS: %+v", awsConfigData)
}
if err := conf.Section("RONGYUN").MapTo(&rongyunData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("TENCENTYUN").MapTo(&tencentyunData); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
mylogrus.MyLog.Info("TENCENTYUN: ", tencentyunData)
}
if err := conf.Section("EMAS").MapTo(&emasData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("AGORA").MapTo(&agora); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("MATCH").MapTo(&matchData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("ONLINE").MapTo(&onlineData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("SESSION").MapTo(&sessionData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("VIDEO").MapTo(&videoData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("BEAN").MapTo(&beanData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("H5").MapTo(&h5Data); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GROUPIM").MapTo(&groupImData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GRADE").MapTo(&gradeData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("LIKE").MapTo(&likeData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("APPLEPAY").MapTo(&applePayData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("REGISTER").MapTo(&registerData); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("BANNER").MapTo(&bannerConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DIAMOND").MapTo(&diamondConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if diamondConfig.NEW_USER_INVITE_AWARD <= 0 {
diamondConfig.NEW_USER_INVITE_AWARD = 5000
}
}
if err := conf.Section("LUCKY_WHEEL").MapTo(&luckyWheelConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GROUP_CUSTOM_THEME").MapTo(&groupCustomThemeConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("GIFT").MapTo(&giftConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("DAILY").MapTo(&dailyConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("CHECKOUT").MapTo(&checkoutConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("PAYER_MAX").MapTo(&payerMaxConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("FRUIT_TYCOON").MapTo(&fruitTycoonConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
// 防止未配置或配置错误
if fruitTycoonConfig.BIG_WINNER_LOW <= 0 {
fruitTycoonConfig.BIG_WINNER_LOW = 10000
}
if fruitTycoonConfig.BIG_WINNER_HIGH <= 0 {
fruitTycoonConfig.BIG_WINNER_HIGH = 20000
}
if fruitTycoonConfig.POOL_RATIO <= 0 || fruitTycoonConfig.POOL_RATIO > 100 {
fruitTycoonConfig.POOL_RATIO = 20
}
if fruitTycoonConfig.WATERMELON_RATIO <= 0 || fruitTycoonConfig.WATERMELON_RATIO > 100 {
fruitTycoonConfig.WATERMELON_RATIO = 70
}
mylogrus.MyLog.Infof("FRUIT_TYCOON: %+v", fruitTycoonConfig)
}
if err := conf.Section("ACTIVITY").MapTo(&activityConfig); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
// 防止未配置或配置错误
if activityConfig.COUNTRY_STAR_POOL_RATIO <= 0 {
activityConfig.COUNTRY_STAR_POOL_RATIO = 20
}
if activityConfig.COUNTRY_STAR_ORDINARY_RATIO <= 0 {
activityConfig.COUNTRY_STAR_ORDINARY_RATIO = 20
}
mylogrus.MyLog.Infof("ACTIVITY: %+v", activityConfig)
}
if err := conf.Section("RISK_CONTROL").MapTo(&riskControl); err != nil {
mylogrus.MyLog.Fatal(err)
} else {
if riskControl.USER_QPS_LIMIT <= 0 {
riskControl.USER_QPS_LIMIT = 128
}
if riskControl.USER_URL_QPS_LIMIT <= 0 {
riskControl.USER_URL_QPS_LIMIT = 64
}
mylogrus.MyLog.Infof("RISK_CONTROL: %+v", riskControl)
}
if err := conf.Section("SUD").MapTo(&sudConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
if err := conf.Section("URL").MapTo(&urlConfig); err != nil {
mylogrus.MyLog.Fatal(err)
}
}
package consul
import (
"fmt"
"github.com/hashicorp/consul/api"
"hilo-user/_const"
"hilo-user/mylogrus"
"net/http"
"os"
"time"
)
const (
RegisterName = "hiloUser"
RegisterTag = "用户中心"
)
// 异步注册到consul
func RegisterToConsul(port int) {
go register(port, false)
go selfCheck(port)
}
func consulCheck(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintln(w, "consulCheck")
}
func register(port int, retry bool) {
client, err := api.NewClient(api.DefaultConfig()) //非默认情况下需要设置实际的参数
if err != nil {
mylogrus.MyLog.Errorf("RegisterToConsul Fail:%v", err)
return
}
if client == nil {
mylogrus.MyLog.Errorf("Fail to get consul client.")
return
}
mylogrus.MyLog.Infof("RegisterToConsul:%v-%v", client, err)
checkPort := port + 1000
registration := new(api.AgentServiceRegistration)
hostName, _ := os.Hostname()
registration.ID = fmt.Sprintf("%s-%s", RegisterName, hostName)
registration.Name = RegisterName
registration.Port = port
registration.Tags = []string{RegisterTag}
myIp, myNodeName := "", ""
if localIp, err := _const.GetClientIp(); err != nil {
mylogrus.MyLog.Fatalln("local ip not found", err)
} else {
myIp = localIp
}
mylogrus.MyLog.Infof("My ip is %s, nodeName: %s\n", myIp, myNodeName)
registration.Address = myIp
registration.Check = &api.AgentServiceCheck{
HTTP: fmt.Sprintf("http://localhost:%d%s", checkPort, "/check"),
Timeout: "3s",
Interval: "5s",
DeregisterCriticalServiceAfter: "30s", //check失败后30秒删除本服务
}
err = client.Agent().ServiceRegister(registration)
if err != nil {
mylogrus.MyLog.Errorf("register server error :%v ", err)
return
}
if !retry {
http.HandleFunc("/check", consulCheck)
if err = http.ListenAndServe(fmt.Sprintf(":%d", checkPort), nil); err != nil {
mylogrus.MyLog.Warnf("check server error :%v ", err)
return
}
}
}
// 自愈检查
// 启动后每一分钟检查一次
// 首次启动不执行
func selfCheck(port int) {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
client, err := api.NewClient(api.DefaultConfig()) //非默认情况下需要设置实际的参数
if err != nil {
mylogrus.MyLog.Errorf("RegisterToConsul Fail:%v", err)
break
}
if client == nil {
mylogrus.MyLog.Errorf("Fail to get consul client.")
break
}
cataLog := client.Catalog()
if cataLog == nil {
mylogrus.MyLog.Errorf("No catalog.")
break
}
services, _, err := cataLog.Service(RegisterName, "", nil)
if err != nil {
mylogrus.MyLog.Errorf("%v", err)
break
}
if len(services) == 0 {
mylogrus.MyLog.Errorf("%s not found.", RegisterName)
go register(port, true) // 重新注册
} else {
mylogrus.MyLog.Infof("%s check success %v", RegisterName, services[0])
}
}
}
}
package consul
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/api/watch"
"hilo-user/mylogrus"
"sync"
)
type ServiceCallback func(serviceStatus map[string]map[string][]string) // service->status->addrs
// 定义watcher
type Watcher struct {
Address string // consul agent 的地址:"127.0.0.1:8500"
Wp *watch.Plan // 总的Services变化对应的Plan
watchers map[string]*watch.Plan // 对已经进行监控的service作个记录
RWMutex *sync.RWMutex
}
// 将consul新增的service加入,并监控
func (w *Watcher) registerServiceWatcher(serviceName string, callback ServiceCallback) error {
// watch endpoint 的请求参数,具体见官方文档:https://www.consul.io/docs/dynamic-app-config/watches#service
wp, err := watch.Parse(map[string]interface{}{
"type": "service",
"service": serviceName,
})
if err != nil {
return err
}
// 定义service变化后所执行的程序(函数)handler
wp.Handler = func(idx uint64, data interface{}) {
switch d := data.(type) {
case []*consulapi.ServiceEntry:
var serviceStatus = make(map[string]map[string][]string)
for _, i := range d {
if data, ok := serviceStatus[i.Service.Service]; ok {
data[i.Checks.AggregatedStatus()] = append(data[i.Checks.AggregatedStatus()], fmt.Sprintf("%s:%d", i.Service.Address, i.Service.Port))
} else {
serviceStatus[i.Service.Service] = make(map[string][]string)
serviceStatus[i.Service.Service][i.Checks.AggregatedStatus()] = append(serviceStatus[i.Service.Service][i.Checks.AggregatedStatus()],
fmt.Sprintf("%s:%d", i.Service.Address, i.Service.Port))
}
}
// 回传到外面
callback(serviceStatus)
mylogrus.MyLog.Infof("consul service status: %s", serviceStatus)
}
}
// 启动监控
go wp.Run(w.Address)
// 对已启动监控的service作一个记录
w.RWMutex.Lock()
w.watchers[serviceName] = wp
w.RWMutex.Unlock()
return nil
}
func newWatcher(watchType string, opts map[string]string, consulAddr string, callback ServiceCallback) (*Watcher, error) {
var options = map[string]interface{}{
"type": watchType,
}
// 组装请求参数。(监控类型不同,其请求参数不同)
for k, v := range opts {
options[k] = v
}
wp, err := watch.Parse(options)
if err != nil {
return nil, err
}
w := &Watcher{
Address: consulAddr,
Wp: wp,
watchers: make(map[string]*watch.Plan),
RWMutex: new(sync.RWMutex),
}
wp.Handler = func(idx uint64, data interface{}) {
switch d := data.(type) {
// 这里只实现了对services的监控,其他监控的data类型判断参考:https://github.com/dmcsorley/avast/blob/master/consul.go
// services
case map[string][]string:
for i := range d {
// 如果该service已经加入到ConsulRegistry的services里监控了,就不再加入 或者i 为 "consul"的字符串
// 为什么会多一个consul,参考官方文档services监听的返回值:https://www.consul.io/docs/dynamic-app-config/watches#services
if _, ok := w.watchers[i]; ok || i == "consul" {
continue
}
w.registerServiceWatcher(i, callback)
}
// 从总的services变化中找到不再监控的service并停止
w.RWMutex.RLock()
watches := w.watchers
w.RWMutex.RUnlock()
// remove unknown services from watchers
for i, svc := range watches {
if _, ok := d[i]; !ok {
svc.Stop()
delete(watches, i)
}
}
default:
mylogrus.MyLog.Errorf("不能判断监控的数据类型: %v", &d)
}
}
return w, nil
}
func RegisterWatcher(watchType string, opts map[string]string, consulAddr string, callback ServiceCallback) error {
w, err := newWatcher(watchType, opts, consulAddr, callback)
if err != nil {
mylogrus.MyLog.Error(err)
return err
}
defer w.Wp.Stop()
if err = w.Wp.Run(consulAddr); err != nil {
mylogrus.MyLog.Errorf("RegisterWatcher err: %v", err)
return err
}
return nil
}
package mysql
import "time"
type EntityI interface {
GetID() ID
//用于判断数据是否进行持久化
IsLazyLoad() bool
//默认值为false true:代表要移除数据
CheckDel() bool
//检查是否唯一键冲突,依旧更新
CheckOnDuplicateKeyUPDATE() bool
//检查是否唯一键冲突,则不插入
CheckOnDuplicateKeyIGNORE() bool
//更新乐观锁 默认值为false true:乐观锁更新
CheckUpdateVersion() bool
//更新条件.
CheckUpdateCondition() bool
//获取版本号
GetUpdateVersionBefore() uint
//更新情况
GetUpdateCondition() string
//save 动作排除字段
GetOmit() []string
}
type Entity struct {
ID ID `gorm:"primary_key"`
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
lazyLoad bool `gorm:"-"`
del bool `gorm:"-"`
onDuplicateKeyUPDATE bool `gorm:"-"`
onDuplicateKeyIGNORE bool `gorm:"-"`
updateVersionFlag bool `gorm:"-"`
updateVersionBefore uint `gorm:"-"`
updateCondition string `gorm:"-"`
omit []string `gorm:"-"` //更新排除
updateColumns map[string]interface{} `gorm:"-"` //更新字段
}
func (t *Entity) GetID() ID {
return t.ID
}
func (t *Entity) IsLazyLoad() bool {
return t.lazyLoad
}
func (t *Entity) SetLasyLoad() {
t.lazyLoad = true
}
func (t *Entity) SetDel() {
t.del = true
}
func (t *Entity) CheckDel() bool {
return t.del
}
func (t *Entity) SetOnDuplicateKeyUPDATE() {
t.onDuplicateKeyUPDATE = true
}
func (t *Entity) SetOnDuplicateKeyIGNORE() {
t.onDuplicateKeyIGNORE = true
}
func (t *Entity) CheckOnDuplicateKeyUPDATE() bool {
return t.onDuplicateKeyUPDATE
}
func (t *Entity) CheckOnDuplicateKeyIGNORE() bool {
return t.onDuplicateKeyIGNORE
}
func (t *Entity) SetCheckUpdateVersionBefore(versionBefore uint) {
t.updateVersionBefore = versionBefore
t.updateVersionFlag = true
}
func (t *Entity) SetCheckUpdateCondition(condition string) {
t.updateCondition = condition
}
func (t *Entity) CheckUpdateVersion() bool {
return t.updateVersionFlag
}
func (t *Entity) CheckUpdateCondition() bool {
return t.updateCondition != ""
}
func (t *Entity) GetUpdateCondition() string {
return t.updateCondition
}
func (t *Entity) GetUpdateVersionBefore() uint {
return t.updateVersionBefore
}
func (t *Entity) GetOmit() []string {
return t.omit
}
func (t *Entity) SetOmit(omit []string) {
t.omit = omit
}
func (t *Entity) SetUpdateColumns(updateColumns map[string]interface{}) {
t.updateColumns = updateColumns
}
func (t *Entity) GetUpdateColumns() map[string]interface{} {
return t.updateColumns
}
package mysql
import (
"context"
"fmt"
. "gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"time"
)
func MyNew(writer Writer, config Config) Interface {
var (
infoStr = "%s[info] "
warnStr = "%s[warn] "
errStr = "%s[error] "
traceStr = "%s[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s[%.3fms] [rows:%v] %s"
)
//if config.Colorful {
// infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset
// warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
// errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
// traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
// traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
// traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
//}
myTraceStr := " traceId:%v userId:%v"
infoStr += myTraceStr
warnStr += myTraceStr
errStr += myTraceStr
traceStr += myTraceStr
traceWarnStr += myTraceStr
traceErrStr += myTraceStr
return &myLogger{
Writer: writer,
Config: config,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
type myLogger struct {
Writer
Config
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
}
// LogMode log mode
func (l *myLogger) LogMode(level LogLevel) Interface {
newlogger := *l
newlogger.LogLevel = level
return &newlogger
}
// Info print info
func (l myLogger) Info(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Info {
l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Warn print warn messages
func (l myLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Warn {
l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Error print error messages
func (l myLogger) Error(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Error {
l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Trace print sql message
func (l myLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
traceId, userId := ctx.Value("traceId"), ctx.Value("userId")
if l.LogLevel > Silent {
elapsed := time.Since(begin)
switch {
case err != nil && l.LogLevel >= Error:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
if rows == -1 {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case l.LogLevel == Info:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
}
}
}
package mysql
import (
"fmt"
_ "github.com/go-sql-driver/mysql" //加载mysql驱动
_ "github.com/joho/godotenv/autoload"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"log"
"net/url"
"time"
)
var Db *gorm.DB
func init() {
var err error
mysqlConfigData := config.GetConfigMysql()
options := "?charset=utf8mb4&parseTime=True&loc=Local&time_zone=" + url.QueryEscape("'+8:00'")
dsn := "" + mysqlConfigData.MYSQL_USERNAME + ":" + mysqlConfigData.MYSQL_PASSWORD + "@(" + mysqlConfigData.MYSQL_HOST + ")/" + mysqlConfigData.MYSQL_DB + options
sqlLogger := logger.Default.LogMode(logger.Info)
if file := mylogrus.GetSqlLog(); file != nil {
//sqlLogger = logger.New(log.New(file, "\r\n", log.Ldate|log.Lmicroseconds), logger.Config{
sqlLogger = MyNew(log.New(file, "", log.Ldate|log.Lmicroseconds), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Info,
Colorful: false,
})
}
Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: sqlLogger,
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
log.Fatalf("mysql connect error %v", err)
} else {
log.Println("mysql connect success")
}
if Db.Error != nil {
fmt.Printf("database error %v", Db.Error)
}
if d, err := Db.DB(); err == nil {
d.SetConnMaxLifetime(time.Minute * 30) // 连接可复用的最大时间。
d.SetMaxIdleConns(20) // 空闲连接数
d.SetMaxOpenConns(20) // 最大连接数
}
}
package mysql
import "strconv"
/**
基于PDM,建立统计的数据domain结构。注意,不要选择0, 因为go的int默认值为0
*/
//主键ID
type ID = uint64
//性别
type Sex = uint8
//加减
type AddReduce = uint8
//拥有
type YesNo = uint8
//短描述
type Str = string
//时间戳
type Time = int64
//状态
type UserYesNo = uint8
//平台
type Platform = uint8
//多枚举类型
type Type = uint8
//数量
type Num = uint32
//时间戳
type Timestamp = uint64
//排序
type Index = uint16
//数量,并且用到-1作为特殊标记位
type NumAll = int
//开启关闭
type OpenClose = uint8
//逻辑删除
type LogicDel = uint8
//设备
type Device = uint8
type PeriodType = uint8
type FinishYesNo = uint8
//性别
const (
MAN Sex = 1
WOMAN Sex = 2
EMPTY Sex = 0
)
//yes no
const (
YES YesNo = 1
NO YesNo = 2
)
const (
OPEN OpenClose = 1
CLOSE OpenClose = 2
)
//加,减
const (
ADD AddReduce = 1
REDUCE AddReduce = 2
NilAddREDUCE AddReduce = 3
)
const (
USER UserYesNo = 1
NOUSER UserYesNo = 2
)
func TypeToString(t Type) string {
return strconv.Itoa(int(t))
}
package redisCli
import (
"context"
"github.com/go-redis/redis/v8"
"hilo-user/mylogrus"
"hilo-user/resource/config"
)
var RedisClient *redis.Client
func init() {
RedisClient = redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 0, // use default DB
PoolSize: 20,
MinIdleConns: 20,
})
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_HOST)
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_PASSWORD)
pong, err := RedisClient.Ping(context.Background()).Result()
if err != nil {
mylogrus.MyLog.Warn(err)
mylogrus.MyLog.Fatal("redis db0 connect fail")
} else {
mylogrus.MyLog.Info("redis db0 connection success - ", pong)
}
}
func GetRedis() *redis.Client {
return RedisClient
}
......@@ -2,9 +2,8 @@ package resp
import (
"encoding/json"
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr"
"net/http"
)
......@@ -113,13 +112,13 @@ func ResponseErrWithString(c *gin.Context, msg interface{}) {
}
func printResponseBody(c *gin.Context, response interface{}) {
traceId, _ := c.Get(_const.TRACEID)
traceId, _ := c.Get(mycontext.TRACEID)
if _traceId, ok := traceId.(string); ok {
c.Header("X-Trace-ID", _traceId)
}
var userId uint64 = 0
if strUserId, ok := c.Get(_const.USERID); ok {
if strUserId, ok := c.Get(mycontext.USERID); ok {
userId = strUserId.(uint64)
}
......
package route
import (
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config"
"github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr"
"hilo-user/req"
"hilo-user/resource/config"
"hilo-user/resp"
)
......@@ -30,9 +29,9 @@ func wrapper(handler HandlerFunc) func(c *gin.Context) {
if myContext == nil {
myContext = mycontext.CreateMyContext(nil)
}
c.Set(_const.ACTION_RESULt, true)
c.Set(mycontext.ACTION_RESULt, true)
if err != nil {
c.Set(_const.ACTION_RESULt, false)
c.Set(mycontext.ACTION_RESULt, false)
reqUri := c.Request.RequestURI
method := c.Request.Method
userId, _ := req.GetUserId(c)
......
......@@ -2,14 +2,13 @@ package route
import (
"bytes"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"github.com/gin-gonic/gin"
"hilo-user/_const"
"hilo-user/mycontext"
"hilo-user/myerr/bizerr"
"hilo-user/mylogrus"
"hilo-user/req"
"hilo-user/req/jwt"
"hilo-user/resource/config"
"hilo-user/resp"
"io/ioutil"
"runtime/debug"
......@@ -78,8 +77,8 @@ func JWTApiHandle(c *gin.Context) {
}
}
c.Set(_const.USERID, claims.UserId)
c.Set(_const.EXTERNAL_ID, claims.ExternalId)
c.Set(mycontext.USERID, claims.UserId)
c.Set(mycontext.EXTERNAL_ID, claims.ExternalId)
c.Writer.Header().Add("token", newToken)
c.Next()
......@@ -93,16 +92,16 @@ func LoggerHandle(c *gin.Context) {
method := c.Request.Method
traceId := genTraceId()
reqUri := c.Request.RequestURI
c.Set(_const.TRACEID, traceId)
c.Set(mycontext.TRACEID, traceId)
//
header := c.Request.Header
//类型
devicetype := header.Get("Devicetype")
c.Set(_const.DEVICETYPE, devicetype)
c.Set(mycontext.DEVICETYPE, devicetype)
appVersion := header.Get("Appversion")
c.Set(_const.APP_VERSION, appVersion)
c.Set(_const.URL, reqUri)
c.Set(_const.METHOD, method)
c.Set(mycontext.APP_VERSION, appVersion)
c.Set(mycontext.URL, reqUri)
c.Set(mycontext.METHOD, method)
userId, _ := req.GetUserId(c)
......
package redis_r
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"hilo-user/domain"
"hilo-user/mycontext"
"hilo-user/mylogrus"
"hilo-user/resource/config"
"strconv"
"strings"
"time"
)
var stop = make(chan struct{})
var match = "match_relation_*"
func Scan(c *gin.Context) (*mycontext.MyContext, error) {
go func() {
return
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
cursor := uint64(0)
first := true
var err error
var keys []string
for first || cursor != 0 {
first = false
select {
case <-stop:
return
default:
keys, cursor, err = model.Redis.Scan(model, cursor, match, 1000).Result()
if err != nil {
model.Log.Errorf("SCAN fail:%v", err)
return
}
var delKeys []string
for _, key := range keys {
arr := strings.Split(key, "_")
if len(arr) == 4 {
cycle, _ := strconv.ParseInt(arr[2], 10, 64)
if cycle > 0 && cycle < 208933198 { // 2022-12-20号
delKeys = append(delKeys, key)
}
}
}
if len(delKeys) > 0 {
cnt, err := model.Redis.Del(model, keys...).Result()
model.Log.Infof("del redis keys:%v,cnt:%v,err:%v", delKeys, cnt, err)
}
time.Sleep(time.Second)
}
}
}()
return mycontext.CreateMyContext(nil), nil
}
func ScanStop(c *gin.Context) (*mycontext.MyContext, error) {
return nil, nil
myCtx := mycontext.CreateMyContext(c.Keys)
stop <- struct{}{}
return myCtx, nil
}
func Hscan(c *gin.Context) (*mycontext.MyContext, error) {
RedisClient := redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 1, // use default DB
PoolSize: 20,
MinIdleConns: 20,
})
cursor := uint64(0)
first := true
var err error
var keys []string
for first || cursor != 0 {
first = false
select {
case <-stop:
return nil, nil
default:
keys, cursor, err = RedisClient.HScan(context.Background(), "user", cursor, "*", 1000).Result()
if err != nil {
return nil, err
}
l := len(keys)
if l%2 != 0 {
mylogrus.MyLog.Errorf("Hscan keys err:%v", keys)
continue
}
for i := 0; i < len(keys); i += 2 {
if !strings.Contains(keys[i+1], "172.26.95.48:50050") && !strings.Contains(keys[i+1], "172.26.95.24:50050") {
res, err := RedisClient.HDel(context.Background(), "user", keys[i]).Result()
msg := fmt.Sprintf("hdel user %v,value:%v,res:%v,err:%v", keys[i], keys[i+1], res, err)
mylogrus.MyLog.Infof("%v", msg)
}
}
}
}
return nil, nil
}
......@@ -5,7 +5,6 @@ import (
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
_ "hilo-user/docs"
"hilo-user/route/redis_r"
"hilo-user/route/user_r"
)
......@@ -20,16 +19,22 @@ func InitRouter() *gin.Engine {
user := v1.Group("/user")
{
user.GET("/nameplate", wrapper(user_r.UserNameplate))
user.GET("/bag/:resType", wrapper(user_r.UserBag))
}
inner := r.Group("/inner")
inner.Use(ExceptionHandle, LoggerHandle)
//}
test := r.Group("/test")
innerUser := inner.Group("/user")
{
//test.GET("/user", wrapper(user_r.Test))
test.GET("/scan/redis", wrapper(redis_r.Scan))
test.GET("/hscan/redis", wrapper(redis_r.Hscan))
test.GET("/scan/redis/stop", wrapper(redis_r.ScanStop))
innerUser.GET("/levels", wrapper(user_r.MGetUserLevels))
innerUser.GET("/bag/id", wrapper(user_r.GetUserBagId))
}
// 道具相关
innerProp := inner.Group("/prop")
{
innerProp.POST("/bag/send", wrapper(user_r.SendUserBag)) // 下发背包道具,暂礼物
innerProp.POST("/noble/send", wrapper(user_r.SendUserNoble)) // 下发贵族
innerProp.POST("/headwear/send", wrapper(user_r.SendUserHeadwear)) // 下发头饰
innerProp.POST("/ride/send", wrapper(user_r.SendUserRide)) // 下发座驾
}
return r
}
package user_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/res_e"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/bag_m"
"hilo-user/domain/model/res_m"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resp"
"strconv"
"time"
)
// @Tags 用户背包
// @Summary 获取用户的背包
// @Param resType path int true "类型:1 礼物"
// @Success 200 {object} []user_cv.UserBag
// @Router /v1/user/bag/{resType} [get]
func UserBag(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
resType, err := strconv.Atoi(c.Param("resType"))
if err != nil {
return myCtx, err
}
var results []user_cv.UserBag
switch res_e.ResUserBag(resType) {
case res_e.ResUserBagGift:
userBagGifts, err := bag_m.GetUserValidUserBag(model, userId, res_e.ResUserBagGift)
if err != nil {
return myCtx, err
}
allValidGifts, err := res_m.FindValidResGiftsMap(model)
if err != nil {
return myCtx, err
}
for _, bagGift := range userBagGifts {
if gift, ok := allValidGifts[bagGift.ResId]; ok {
results = append(results, user_cv.UserBag{
BagId: bagGift.ID,
ResType: res_e.ResUserBagGift,
ResId: gift.ID,
GiftId: gift.ID,
Name: gift.Name,
DiamondNum: gift.DiamondNum,
IconUrl: gift.IconUrl,
SvgaUrl: gift.SvagUrl,
Count: bagGift.Count,
RemainDays: int(bagGift.EndTime.Sub(time.Now()).Hours() / 24),
})
}
}
default:
return myCtx, bizerr.InvalidParameter
}
resp.ResponseOk(c, results)
return myCtx, nil
}
package user_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/cv/user_cv"
"hilo-user/domain/model/bag_m"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/resp"
"time"
)
type MGetUserLevelReq struct {
Ids []mysql.ID `form:"ids" binding:"required"`
}
// @Tags 用户-内部
// @Summary 批量获取用户等级
// @Param ids query string true "用户id,如:ids=1&ids=2&ids=3"
// @Success 200 {object} user_cv.MGetUserLevelData
// @Router /inner/user/levels [get]
func MGetUserLevels(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req MGetUserLevelReq
if err := c.ShouldBindQuery(&req); err != nil {
return myCtx, err
}
wealthGrade, err := user_m.MGetWealthGrade(model, req.Ids)
if err != nil {
return myCtx, err
}
charmGrade, err := user_m.MGetCharmGrade(model, req.Ids)
response := user_cv.MGetUserLevelData{}
for _, userId := range req.Ids {
response[userId] = user_cv.CvUserLevel{
UserId: userId,
WealthUserGrade: wealthGrade[userId],
CharmUserGrade: charmGrade[userId],
}
}
resp.ResponseOk(c, response)
return myCtx, nil
}
type GetUserBagReq struct {
BagId mysql.ID `form:"bagId" binding:"required"`
}
// @Tags 用户-内部
// @Summary 获取单个背包
// @Param bagId query int true "背包id"
// @Success 200 {object} user_cv.UserBag
// @Router /inner/user/bag/id [get]
func GetUserBagId(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req GetUserBagReq
if err := c.ShouldBindQuery(&req); err != nil {
return myCtx, err
}
bag, err := bag_m.GetUserBag(model, req.BagId)
if err != nil {
return myCtx, err
}
gift, err := res_m.FindResGift(model, bag.ResId)
if err != nil {
return myCtx, err
}
resp.ResponseOk(c, user_cv.UserBag{
BagId: bag.ID,
ResType: bag.ResType,
ResId: bag.ResId,
GiftId: bag.ResId,
Name: gift.Name,
DiamondNum: gift.DiamondNum,
IconUrl: gift.IconUrl,
SvgaUrl: gift.SvagUrl,
Count: bag.Count,
RemainDays: int(bag.EndTime.Sub(time.Now()).Hours() / 24),
})
return myCtx, nil
}
package user_r
import (
"errors"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/domain/model/bag_m"
"hilo-user/domain/service/headwear_s"
"hilo-user/domain/service/noble_s"
"hilo-user/domain/service/ride_s"
"hilo-user/resp"
)
type SendUserBagReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
ResType mysql.Type `form:"resType" binding:"required"` // 道具类型 1:礼物道具
ResId mysql.ID `form:"resId" binding:"required"` // 道具资源id
Count mysql.Num `form:"count" binding:"min=1"` // 下发数量
Day int `form:"day" binding:"min=1"` // 天数
Reason string `form:"reason" binding:"required"` // 原因
}
// @Tags 用户-内部
// @Summary 发送背包道具
// @Param userId formData int true "用户id"
// @Param resType formData int true "道具类型 1:礼物道具"
// @Param resId formData int true "道具资源id"
// @Param count formData int true "下发数量"
// @Param day formData int true "天数"
// @Param reason formData string true "原因"
// @Success 200
// @Router /inner/prop/bag/send [post]
func SendUserBag(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var model = domain.CreateModelContext(myCtx)
var req SendUserBagReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
//var bagId mysql.ID
var err error
switch req.ResType {
case mysql.Type(1):
if _, err = bag_m.AddUserBag(model, req.UserId, req.ResType, req.ResId, req.Count, req.Day, req.Reason); err != nil {
return myCtx, err
}
default:
return myCtx, errors.New("un support type")
}
//userBag, err := bag_m.GetUserBag(model, bagId)
//if err != nil {
// return myCtx, err
//}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserNobleReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
Level uint16 `form:"level" binding:"min=1,max=5"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户贵族
// @Param userId formData int true "用户id"
// @Param level formData int true "贵族等级"
// @Param day formData int true "下发天数"
// @Success 200
// @Router /inner/prop/noble/send [post]
func SendUserNoble(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserNobleReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := noble_s.NewNobleService(myCtx).SendNoble(req.UserId, req.Level, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserHeadwearReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
HeadwearId mysql.ID `form:"headwearId" binding:"required"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户头饰
// @Param userId formData int true "用户id"
// @Param headwearId formData int true "头饰id"
// @Param day formData int true "天数"
// @Success 200
// @Router /inner/prop/headwear/send [post]
func SendUserHeadwear(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserHeadwearReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := headwear_s.NewHeadwearService(myCtx).SendHeadwear(req.UserId, req.HeadwearId, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
type SendUserRideReq struct {
UserId mysql.ID `form:"userId" binding:"required"`
RideId mysql.ID `form:"rideId" binding:"required"`
Day int `form:"day" binding:"min=1"`
}
// @Tags 用户-内部
// @Summary 发送用户座驾
// @Param userId formData int true "用户id"
// @Param rideId formData int true "座驾id"
// @Param day formData int true "天数"
// @Success 200
// @Router /inner/prop/ride/send [post]
func SendUserRide(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
var req SendUserRideReq
if err := c.ShouldBind(&req); err != nil {
return myCtx, err
}
if err := ride_s.NewRideService(myCtx).SendRide(req.UserId, req.RideId, req.Day); err != nil {
return myCtx, err
}
resp.ResponseOk(c, struct{}{})
return myCtx, nil
}
package user_r
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-user/domain"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/mycontext"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/resource/mysql"
"hilo-user/resp"
)
......
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