Commit 5b2e24f8 authored by hujiebin's avatar hujiebin

Merge branch 'feature/room-visitor-up' into 'master'

Feature/room visitor up

See merge request !78
parents 0d54c5ee ceda79f5
......@@ -5,9 +5,11 @@ import (
"hilo-group/cron/gift_cron"
"hilo-group/cron/group_cron"
"hilo-group/cron/mic_cron"
"hilo-group/cron/user_cron"
)
func Init() {
user_cron.LoadSvipVipNoble() // 加载用户特权
if !config.IsMaster() {
return
}
......
package user_cron
import (
"git.hilo.cn/hilo-common/domain"
"github.com/robfig/cron"
"hilo-group/domain/cache/user_c"
)
// 加载数据到lru
func LoadSvipVipNoble() {
go user_c.LoadAllSvipVipNoble(domain.CreateModelNil()) // 启动先执行一次
c := cron.New()
spec := "0 */30 * * * ?"
_ = c.AddFunc(spec, func() {
model := domain.CreateModelNil()
user_c.LoadAllSvipVipNoble(model)
})
c.Start()
}
package user_c
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"sync"
"time"
)
type UserLevel struct {
UserId mysql.ID
Level int
}
var svipVipNobleLock sync.RWMutex
var svipLevel = make(map[mysql.ID]int) // userId->svipLevel
var nobleLevel = make(map[mysql.ID]uint16) // userId->nobleLevel
var userVips = make(map[mysql.ID]bool) // userId->isVip
// 加载数据到lru
func LoadAllSvipVipNoble(model *domain.Model) {
start := time.Now()
var svips []UserLevel
svipMap := make(map[mysql.ID]int)
if err := model.DB().Table("user_svip").Select("user_id,level").Where("level > 0").Find(&svips).Error; err != nil {
model.Log.Errorf("LoadAllSvip fail:%v", err)
} else {
for _, v := range svips {
svipMap[v.UserId] = v.Level
}
}
var nobles []UserLevel
nobleMap := make(map[mysql.ID]uint16)
if err := model.DB().Table("user_noble").Select("user_id,MAX(level) level").
Where("level > 0 AND end_time > ?", time.Now()).Find(&nobles).Error; err != nil {
model.Log.Errorf("LoadAllNoble fail:%v", err)
} else {
for _, v := range nobles {
nobleMap[v.UserId] = uint16(v.Level)
}
}
var vips []UserLevel
vipMap := make(map[mysql.ID]bool)
if err := model.DB().Table("user_vip").Select("user_id").
Where("expire_at > ?", time.Now()).Find(&vips).Error; err != nil {
model.Log.Errorf("LoadAllVip fail:%v", err)
} else {
for _, v := range vips {
vipMap[v.UserId] = true
}
}
// 上锁赋值
svipVipNobleLock.Lock()
svipLevel = svipMap
nobleLevel = nobleMap
userVips = vipMap
svipVipNobleLock.Unlock()
model.Log.Infof("LoadAllSvipVipNoble svip:%v,vip:%v,noble:%v,cost:%vs", len(svipMap), len(vipMap), len(nobleMap), time.Now().Sub(start).Seconds())
}
func BatchGetNobleLevel(model *domain.Model, userIds []uint64) map[uint64]uint16 {
res := make(map[uint64]uint16)
svipVipNobleLock.RLock()
defer svipVipNobleLock.RUnlock()
for _, userId := range userIds {
res[userId] = nobleLevel[userId]
}
return res
}
func MGetUserSvipLevel(model *domain.Model, userIds []uint64) map[uint64]int {
res := make(map[uint64]int)
svipVipNobleLock.RLock()
defer svipVipNobleLock.RUnlock()
for _, userId := range userIds {
res[userId] = svipLevel[userId]
}
return res
}
func BatchGetVips(model *domain.Model, userIds []uint64) map[uint64]*int64 {
res := make(map[uint64]*int64)
svipVipNobleLock.RLock()
defer svipVipNobleLock.RUnlock()
for _, userId := range userIds {
vip := int64(1)
if userVips[userId] {
res[userId] = &vip
}
}
return res
}
......@@ -144,3 +144,24 @@ func GetUsers(model *domain.Model, ids []mysql.ID) ([]*User, error) {
}
return res, nil
}
// 获取用户externalIds
// return []externalIds map[userId]extId map[userId]code
func GetUserExternalIds(model *domain.Model, userIds []mysql.ID) ([]string, map[uint64]string, map[uint64]string) {
var res []string
var m = make(map[uint64]string)
var c = make(map[uint64]string)
if len(userIds) <= 0 {
return res, m, c
}
var users []User
if err := model.DB().Model(User{}).Where("id in (?)", userIds).Select("id,external_id").Find(&users).Error; err != nil {
model.Log.Errorf("GetUserExternalIds fail:%v", err)
}
for _, user := range users {
res = append(res, user.ExternalId)
m[user.ID] = user.ExternalId
c[user.ID] = user.Code
}
return res, m, c
}
......@@ -20,6 +20,7 @@ import (
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/user_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
......@@ -988,6 +989,163 @@ func GetGroupVisitors(c *gin.Context) (*mycontext.MyContext, error) {
return myContext, nil
}
// @Tags 群组
// @Summary 最近访问列表
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} GetGroupVisitorsRsp
// @Router /v1/imGroup/visitors/{groupId} [get]
func GetGroupVisitorsV2(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.ParaMissing
}
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
// 获取最近进房用户
rows := group_c.GetLastRoomVisitors(model, groupId)
userIds := make([]uint64, 0)
for _, u := range rows {
userIds = append(userIds, u)
}
result := GetGroupVisitorsRsp{Total: uint(len(userIds))}
beginPos := pageSize * (pageIndex - 1)
if uint(beginPos) < result.Total {
// 取在线状态
extIds, userExtIdMap, userCodeMap := user_m.GetUserExternalIds(model, userIds)
statusMap, err := tim_m.GetOnlineStatus(model, extIds)
if err != nil {
return myContext, err
}
result.Online = 0
for _, v := range statusMap {
if v == online_e.IM_STATUS_ON_LINE {
result.Online++
}
}
// 获取群组角色
roles, _, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
// 获取贵族
nobleLevels := user_c.BatchGetNobleLevel(model, userIds)
// 获取svip
svipLevels := user_c.MGetUserSvipLevel(model, userIds)
// 获取svip
vips := user_c.BatchGetVips(model, userIds)
roomUsers, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return myContext, err
}
roomUserMap := utils.SliceToMapUInt64(roomUsers)
// 排序规则 :在房间的优先,其次是在线,再次看角色,最后看贵族
sort.Slice(userIds, func(i, j int) bool {
ui := userIds[i]
uj := userIds[j]
_, ok1 := roomUserMap[ui]
_, ok2 := roomUserMap[uj]
if ok1 && !ok2 {
return true
} else if ok1 == ok2 {
ei := userExtIdMap[ui]
ej := userExtIdMap[uj]
if statusMap[ei] > statusMap[ej] {
return true
}
if statusMap[ei] == statusMap[ej] {
if roles[ui] > roles[uj] {
return true
}
if roles[ui] == roles[uj] {
// SVIP>贵族5>贵族4>贵族3>贵族2>VIP
if svipLevels[ui] > svipLevels[uj] {
return true
} else if svipLevels[ui] == svipLevels[uj] {
if nobleLevels[ui] > nobleLevels[uj] && nobleLevels[ui] >= 2 {
return true
}
if nobleLevels[ui] == nobleLevels[uj] || nobleLevels[ui] < 2 && nobleLevels[uj] < 2 {
if vips[ui] != nil {
if vips[uj] == nil {
return true
} else {
return userCodeMap[ui] < userCodeMap[uj]
}
} else if vips[uj] == nil {
return userCodeMap[ui] < userCodeMap[uj]
}
}
}
}
}
}
return false
})
endPos := pageSize * pageIndex
if endPos > len(userIds) {
endPos = len(userIds)
}
userIds = userIds[beginPos:endPos]
userExtends, err := user_cv.BatchGetUserExtend(model, userIds, userId) // 这里只是取出pageSize=10条数据
if err != nil {
return myContext, err
}
for _, u := range userIds {
inRoom := false
if _, ok := roomUserMap[u]; ok {
inRoom = true
}
result.Members = append(result.Members, group_cv.GroupVisitorsDetail{
CvGroupMember: user_cv.CvUserExtendToCvGroupMember(userExtends[u]),
Role: roles[u],
OnlineStatus: statusMap[userExtIdMap[u]],
InRoom: inRoom,
})
}
}
resp.ResponseOk(c, result)
// 清理15天之前的访客,定期
if time.Now().Second() == 0 {
group_c.RemoveRoomVisitors(model, groupId)
}
return myContext, nil
}
type OwnPublicGroupRsp struct {
Total uint `json:"total"`
MyGroups []group_cv.GroupDetail `json:"myGroups"`
......
......@@ -43,6 +43,7 @@ func InitRouter() *gin.Engine {
imGroup.GET("/myPermanent", wrapper(group_r.GetMyGroup))
//
imGroup.GET("/visitors/:groupId", wrapper(group_r.GetGroupVisitors))
imGroup.GET("/visitors2/:groupId", wrapper(group_r.GetGroupVisitorsV2))
imGroup.GET("/ownPublicGroup/:userExternalId", wrapper(group_r.GetOwnPublicGroup))
//// 2.19的新接口
imGroup.GET("/ownGroup", wrapper(group_r.GetOwnGroup))
......
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