Commit 76ea952d authored by hujiebin's avatar hujiebin

feat:hiloGroup

parent 65297deb
package game_e
import "fmt"
type GameType uint32
var GameLudoDiamondList = []uint32{0, 100, 500, 1000, 5000, 10000}
......@@ -8,3 +10,9 @@ const (
GameTypeLudo GameType = 1 // ludo
GameTypeUno GameType = 2 // uno
)
const GameAutoMathEnterRoom = "game:autoEnter:%d:%s" // 快速游戏,进入某个房间
func GetAutoMathEnterRoom(userId uint64, imGroupId string) string {
return fmt.Sprintf(GameAutoMathEnterRoom, userId, imGroupId)
}
package task_e
import "git.hilo.cn/hilo-common/resource/mysql"
type RateTypeTaskConfig = mysql.Type
const (
Daily RateTypeTaskConfig = 1
OnlyOne RateTypeTaskConfig = 2
)
type TypeTaskConfig = mysql.Type
const (
MicIn TypeTaskConfig = 1 //上麦10分钟
SendGift TypeTaskConfig = 2 //送礼物
SendGift5Person TypeTaskConfig = 3 //给5个人送出礼物
GroupImMass TypeTaskConfig = 4 //发布会员广播
SendGlobalBroadcast TypeTaskConfig = 5 //发布全球广播
PayFirst TypeTaskConfig = 6 //首次充值
Level5 TypeTaskConfig = 7 //任意等级达到5级(财富,活跃,魅力)
WatchAd TypeTaskConfig = 8 // 观看广告
VideoChat TypeTaskConfig = 9 // 视频任务(暂只统计匹配)
)
package mic_k
import (
"fmt"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/redis_key"
"time"
)
const (
MicPrefix = "mic:"
MicDayInvite = MicPrefix + "day:invite:${userId}:${date}" // string 自动被邀请上麦,1天一次,TTL:24H
)
func GetUserMicDayInvite(userId mysql.ID) string {
date := time.Now().Format("2006-01-02")
return redis_key.ReplaceKey(MicDayInvite, fmt.Sprintf("%d", userId), date)
}
......@@ -206,6 +206,29 @@ type RoomMedalInfo struct {
Desc string `json:"desc"`
}
type GroupChannelId struct {
ChannelId string `json:"channelId"`
Token string `json:"token"`
AgoraId uint32 `json:"agoraId"`
MicNumType uint8 `json:"micNumType"`
}
//国籍视图
type CvCountry struct {
//名字
Name *string `json:"name"`
//缩写
ShortName *string `json:"shortName"`
//图标地址
Icon *string `json:"icon"`
//code
Code *string `json:"code"`
// 手机区号
AreaCode *string `json:"areaCode"`
//手机号国家域名缩写
AreaCodeName *string `json:"areaShortName"`
}
func BuildJoinedGroupInfo(myService *domain.Service, myUserId uint64, groupIds []string, pageSize, pageIndex int) ([]JoinedGroupInfo, int, error) {
model := domain.CreateModel(myService.CtxAndDb)
......
package group_cv
import (
"hilo-group/domain/model/group_m"
"time"
)
//麦位信息,
type CvMic struct {
//麦位
I int `json:"i"`
//锁,是否有锁 true:锁了, false:没锁
Lock bool `json:"lock"`
//静音 true:静音,false:没有静音
Forbid bool `json:"forbid"`
//如果 nil 则代表这个位置上没有人
ExternalId *string `json:"externalId"`
//声网agoraId 如果 nil 则代表这个位置上没有人
AgoraId *uint32 `json:"agoraId"`
//上麦时间戳
Timestamp int64 `json:"timestamp"`
}
//获取群组中所有的mic位信息
func GetGroupMicAll(mics []group_m.Mic, micUsers []group_m.MicUser) ([]CvMic, error) {
timestamp := time.Now().Unix()
micUserMap := map[int]*group_m.MicUser{}
for i := 0; i < len(micUsers); i++ {
micUserMap[micUsers[i].I] = &(micUsers[i])
}
//
var cvMics []CvMic
for _, v := range mics {
forbid := false
var externalId *string = nil
var agoraId *uint32 = nil
if u, ok := micUserMap[v.I]; ok {
forbid = u.Forbid
externalId = &u.ExternalId
tmp := uint32(u.UserId)
agoraId = &tmp
}
cvMics = append(cvMics, CvMic{
I: v.I,
Lock: v.Lock,
Forbid: forbid,
ExternalId: externalId,
AgoraId: agoraId,
Timestamp: timestamp,
})
}
return cvMics, nil
}
package mic_cv
//麦位表情
type CvMicEmoji struct {
//Id
Id uint64 `json:"id"`
//名字
Name string `json:"name"`
//图片地址
IconUrl string `json:"iconUrl"`
//特效地址
SvagUrl string `json:"svagUrl"`
}
......@@ -232,3 +232,71 @@ func GetPropertyList(db *gorm.DB, userId uint64) ([]CvProperty, error) {
}
return result, nil
}
type PropertyExt struct {
Id uint64
PicUrl mysql.Str
EffectUrl mysql.Str
Using bool
TimeLeft int64 // 离到期还有多少秒(过期则是负数)
SenderAvatar string
ReceiverAvatar string
}
func GetExtendedProperty(db *gorm.DB) (map[uint64]PropertyExt, error) {
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
//获取座驾头像
propertieAvatarMap, err := (&res_m.ResPropertyAvatar{}).GetAll(mysql.Db)
userIds := []uint64{}
for _, value := range propertieAvatarMap {
if value.SendUserId > 0 {
userIds = append(userIds, value.SendUserId)
}
if value.ReceiverUserId > 0 {
userIds = append(userIds, value.ReceiverUserId)
}
}
//获取用户信息
users := []user_m.User{}
if err := db.Model(&user_m.User{}).Where("id in (?)", userIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userAvatarMap := map[mysql.ID]string{}
for _, r := range users {
userAvatarMap[r.ID] = r.Avatar
}
result := map[uint64]PropertyExt{}
for _, r := range properties {
var senderAvatar string = ""
var receiverAvatar string = ""
if propertieAvatar, flag := propertieAvatarMap[r.ID]; flag {
if propertieAvatar.SendUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.SendUserId]; flag {
senderAvatar = avatar
}
}
if propertieAvatar.ReceiverUserId > 0 {
if avatar, flag := userAvatarMap[propertieAvatar.ReceiverUserId]; flag {
receiverAvatar = avatar
}
}
}
result[r.ID] = PropertyExt{
Id: r.ID,
PicUrl: r.PicUrl,
EffectUrl: r.EffectUrl,
SenderAvatar: senderAvatar,
ReceiverAvatar: receiverAvatar,
}
}
return result, nil
}
package game_c
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/resource/redisCli"
"hilo-group/_const/enum/game_e"
"time"
)
type gameAutoJoinMsg struct {
TraceId string
Token string
EnterType string
GameCode string
}
func SetAutoMathEnterRoom(userId uint64, imGroupId, traceId, token, enterType, gameCode string) error {
key := game_e.GetAutoMathEnterRoom(userId, imGroupId)
info := gameAutoJoinMsg{traceId, token, enterType, gameCode}
data, err := json.Marshal(info)
if err != nil {
return err
}
err = redisCli.GetRedis().LPush(context.Background(), key, data).Err()
if err != nil {
return err
}
redisCli.GetRedis().Expire(context.Background(), key, time.Second*3)
return nil
}
func IsAutoMathEnterRoom(userId uint64, imGroupId string) (bool, string, string, string, string) {
key := game_e.GetAutoMathEnterRoom(userId, imGroupId)
data, err := redisCli.GetRedis().RPop(context.Background(), key).Bytes()
if err != nil {
return false, "", "", "", ""
}
info := gameAutoJoinMsg{}
err = json.Unmarshal(data, &info)
if err != nil {
return false, "", "", "", ""
}
if info.Token != "" && info.TraceId != "" && info.EnterType != "" && info.GameCode != "" {
redisCli.GetRedis().Del(context.Background(), key)
return true, info.TraceId, info.Token, info.EnterType, info.GameCode
}
return false, "", "", "", ""
}
......@@ -62,20 +62,9 @@ func addGroupMember(groupId string, extIds []string) (int64, error) {
return redisCli.RedisClient.SAdd(context.Background(), key, extIds).Result()
}
func AddGroupMember(model *domain.Model, groupId string, extId string) error {
func AddGroupMember(groupId string, extIds []string) (int64, error) {
key := getGroupMemberKey(groupId)
ret, err := redisCli.RedisClient.Exists(context.Background(), key).Result()
if err != nil {
model.Log.Infof("AddGroupMember %s, skip because set does not exist", groupId)
return err
}
if ret == 0 {
// 集合不存在,不要加进去!
return nil
}
ret, err = addGroupMember(groupId, []string{extId})
model.Log.Infof("AddGroupMember %s, %s ret = %d, err: %v", groupId, extId, ret, err)
return err
return redisCli.RedisClient.SAdd(context.Background(), key, extIds).Result()
}
func RemoveGroupMember(groupId string, externalId string) (int64, error) {
......
package mic_c
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/_const/redis_key/mic_k"
"time"
)
// 增加上麦邀请次数,一天只需要第一次进房弹出
// return show:true 今天已经展示过了
func IsMicDayInviteDialogShowToday(model *domain.Model, userId mysql.ID) (show bool, err error) {
key := mic_k.GetUserMicDayInvite(userId)
ttl := time.Hour * 24
if !config.AppIsRelease() {
ttl = time.Hour
}
lock, err := model.Redis.SetNX(model, key, 1, ttl).Result()
if err != nil {
model.Log.Errorf("IsMicDayInviteDialogShowToday uid:%v, fail:%v", userId, err)
return false, err
}
// !lock = show
return !lock, err
}
......@@ -12,6 +12,37 @@ import (
"time"
)
// 处理访问房间的相关缓存
func ProcessRoomVisit(groupId string, userId uint64) error {
key := redis_key.GetPrefixGroupInUserDuration(groupId)
now := time.Now()
ret, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{
Score: float64(now.Unix()),
Member: userId,
}).Result()
if err != nil {
return err
}
mylogrus.MyLog.Infof("ProcessRoomVisit, ZADD %s, return %d", key, ret)
// 每群定时清一次数据可以了
if now.Second()%redis_key.GroupInDurationClearPeriod == 0 {
rc, err := clearRoomVisit(groupId, now.AddDate(0, 0, -redis_key.GroupInDurationTTL))
if err == nil {
mylogrus.MyLog.Infof("ProcessRoomVisit, clearRoomVisit %s, return %d", key, rc)
} else {
mylogrus.MyLog.Warnf("ProcessRoomVisit, clearRoomVisit %s, failed %s", key, err.Error())
}
}
// 马上更新roomVisitCount
if _, err := GetSetRoomVisitCount(groupId); err != nil {
mylogrus.MyLog.Warnf("ProcessRoomVisit, failed for key %s, err: %s", key, err.Error())
}
return nil
}
func ProcessUserRoomVisit(userId uint64, groupId string) error {
key := redis_key.GetUserEnterRoomKey(userId)
now := time.Now()
......@@ -80,3 +111,17 @@ func saveRoomVisitCount(groupId string, count int64) (int64, error) {
key := redis_key.GetPrefixRoomVisitCount()
return redisCli.GetRedis().HSet(context.Background(), key, groupId, strconv.FormatInt(count, 10)).Result()
}
func clearRoomVisit(groupId string, t time.Time) (int64, error) {
value := strconv.FormatInt(t.Unix(), 10)
ret, err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetPrefixGroupInUserDuration(groupId), "0", value).Result()
if err != nil {
return 0, err
}
return ret, nil
}
func GetAllRoomVisitCount() (map[string]string, error) {
key := redis_key.GetPrefixRoomVisitCount()
return redisCli.GetRedis().HGetAll(context.Background(), key).Result()
}
package tim_c
import (
"git.hilo.cn/hilo-common/domain"
"hilo-group/domain/cache/group_c"
"time"
)
func setGroupMember(model *domain.Model, groupId string, extIds []string) error {
err := BatchAddGroupMember(model, groupId, extIds)
if err == nil {
ret, err := group_c.SetGroupMemberTTL(groupId, time.Hour)
model.Log.Infof("SetGroupMemberTTL %s, ret = %t, err: %v", groupId, ret, err)
}
return err
}
func BatchAddGroupMember(model *domain.Model, groupId string, extIds []string) error {
ret, err := group_c.AddGroupMember(groupId, extIds)
model.Log.Infof("BatchAddGroupMember %s, %v ret = %d, err: %v", groupId, extIds, ret, err)
return err
}
func AddGroupMember(model *domain.Model, groupId string, extId string) error {
ret, err := group_c.SetExists(groupId)
if err != nil {
model.Log.Infof("AddGroupMember %s, skip because set does not exist", groupId)
return err
}
if ret == 0 {
// 集合不存在,不要加进去!
return nil
}
ret, err = group_c.AddGroupMember(groupId, []string{extId})
model.Log.Infof("AddGroupMember %s, %s ret = %d, err: %v", groupId, extId, ret, err)
return err
}
func RemoveGroupMember(model *domain.Model, groupId string, extId string) error {
ret, err := group_c.RemoveGroupMember(groupId, extId)
model.Log.Infof("RemoveGroupMember %s, %s ret = %d, err: %v", groupId, extId, ret, err)
return err
}
func GetGroupMemberCount(model *domain.Model, groupId string) (uint, error) {
ret, err := group_c.GetGroupMemberCard(groupId)
model.Log.Infof("GetGroupMemberCount %s, ret = %d, err: %v", groupId, ret, err)
return uint(ret), err
}
package group_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type BuyGroupCustomThemeEvent struct {
GroupCustomThemeId mysql.ID
UserId mysql.ID
}
//注册监听
var buyGroupCustomThemeListen = new(domain.EventBase)
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddBuyGroupCustomThemeSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(buyGroupCustomThemeListen, callback)
}
//加入到异步操作中
func AddBuyGroupCustomThemeAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(buyGroupCustomThemeListen, callback)
}
//领域事件发布
func PublishBuyGroupCustomTheme(model *domain.Model, event *BuyGroupCustomThemeEvent) error {
return domain.PublishEvent(buyGroupCustomThemeListen, model, event)
}
package group_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
/**
* IM群发
*/
type GroupImMassEvent struct {
GroupId string
UserId mysql.ID
Members []uint64
Content string
}
//注册监听
var groupImMassListen = new(domain.EventBase)
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGroupImMassSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(groupImMassListen, callback)
}
//加入到异步操作中
func AddGroupImMassAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(groupImMassListen, callback)
}
//领域事件发布
func PublishGroupImMass(model *domain.Model, event *GroupImMassEvent) error {
return domain.PublishEvent(groupImMassListen, model, event)
}
package group_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type GroupInEvent struct {
GroupId string
UserId mysql.ID
ExternalId string
Nick string
Avatar string
IsMember bool //是否永久成员
IsVip bool
NobleLevel uint16
}
//注册监听
var groupInListen = new(domain.EventBase)
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGroupInSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(groupInListen, callback)
}
//加入到异步操作中
func AddGroupInAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(groupInListen, callback)
}
//领域事件发布
func PublishGroupIn(model *domain.Model, event *GroupInEvent) error {
return domain.PublishEvent(groupInListen, model, event)
}
package group_ev
import (
"git.hilo.cn/hilo-common/domain"
)
/**
*
*/
type GroupKickOutEvent struct {
GroupId string
OperatorExternalId string `json:"operatorExternalId"`
OperatorName string `json:"operatorName"`
OperatorFaceUrl string `json:"operatorFaceUrl"`
MemberExternalId string `json:"memberExternalId"`
MemberName string `json:"memberName"`
MemberAvatar string `json:"memberAvatar"`
}
//注册监听
var groupKickOutListen = new(domain.EventBase)
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGroupKickOutSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(groupKickOutListen, callback)
}
//加入到异步操作中
func AddGroupKickOutAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(groupKickOutListen, callback)
}
//领域事件发布
func PublishGroupKickOut(model *domain.Model, event interface{}) error {
return domain.PublishEvent(groupKickOutListen, model, event)
}
......@@ -268,3 +268,13 @@ func (diamondAccountDetail *DiamondAccountDetail) Persistent() error {
func (diamondAccount *DiamondAccount) GroupSupportMgr(groupSupportAwardId mysql.ID, diamondNum uint32) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(diamond_e.GroupSupportMgr, groupSupportAwardId, diamondNum)
}
//群组IM群发
func (diamondAccount *DiamondAccount) GroupImMass() (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(diamond_e.GroupIMMass, 0, 0)
}
//购买自定义群组主题
func (diamondAccount *DiamondAccount) BuyGroupCustomTheme(diamondAccountDetailId mysql.ID) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(diamond_e.GroupCustomTheme, diamondAccountDetailId, 0)
}
......@@ -457,7 +457,7 @@ type UserEnterRoom struct {
EnterTime time.Time
}
func (uer *UserEnterRoom) save(db *gorm.DB) error {
func (uer *UserEnterRoom) Save(db *gorm.DB) error {
return db.Clauses(clause.OnConflict{UpdateAll: true}).Create(uer).Error
}
......
package mgr_m
import (
"hilo-group/domain/model"
"hilo-group/myerr"
)
func (mgrReportGroup *MgrReportGroup) Persistent() error {
if err := model.Persistent(mgrReportGroup.Db, mgrReportGroup); err != nil {
return myerr.WrapErr(err)
}
return nil
}
package mgr_m
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/mgr_e"
"hilo-group/myerr"
)
//投诉
type MgrReport struct {
mysql.Entity
*domain.Model `gorm:"-"`
FromUserId mysql.ID
ToUserId mysql.ID
FromPageType mgr_e.ReportPageType
ReasonType mgr_e.ReportReasonType
OriginId mysql.ID
ImageUrl mysql.Str
Reason mysql.Str
Status mgr_e.ReportStatus
ReportDealId mysql.ID
}
//投诉-群组
type MgrReportGroup struct {
mysql.Entity
*domain.Model `gorm:"-"`
FromUserId mysql.ID
GroupId mysql.Str
ReasonType mgr_e.ReportReasonType
ImageUrl mysql.Str
Reason mysql.Str
Status mgr_e.ReportStatus
ReportDealId mysql.ID
}
func ReportAdd(model *domain.Model, fromUserId mysql.ID, toUserId mysql.ID, fromPageType mgr_e.ReportPageType, originId mysql.ID, reasonType mgr_e.ReportReasonType, imageUrl mysql.Str, reason mysql.Str) *MgrReport {
return &MgrReport{
Model: model,
FromUserId: fromUserId,
ToUserId: toUserId,
FromPageType: fromPageType,
ReasonType: reasonType,
OriginId: originId,
ImageUrl: imageUrl,
Reason: reason,
Status: mgr_e.NoDealReportStatus,
}
}
func ReportGroupAdd(model *domain.Model, fromUserId mysql.ID, groupId mysql.Str, reasonType mgr_e.ReportReasonType, imageUrl mysql.Str, reason mysql.Str) *MgrReportGroup {
return &MgrReportGroup{
Model: model,
FromUserId: fromUserId,
GroupId: groupId,
ReasonType: reasonType,
ImageUrl: imageUrl,
Reason: reason,
Status: mgr_e.NoDealReportStatus,
}
}
//检查投诉
func checkReport(model *domain.Model, reportId mysql.ID) (*MgrReport, error) {
//var report = new(MgrReport)
var report MgrReport
if err := model.Db.First(&report, reportId).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, myerr.NewSysError("投诉不存在, Id:" + fmt.Sprintf("%d", reportId))
} else {
return nil, myerr.WrapErr(err)
}
}
/* if report.Status == mgr_m.HasDealReportStatus {
return nil, myerr.NewSysError("投诉已被处理。, Id:" + mysql.IdToStr(reportId))
}*/
return &report, nil
}
//投诉处理
func ReportDeal(model *domain.Model, reportId mysql.ID) (*MgrReport, error) {
report, err := checkReport(model, reportId)
if err != nil {
return nil, err
}
report.Status = mgr_e.HasDealReportStatus
return report, nil
}
func GetMyReport(userId mysql.ID) ([]uint64, error) {
users := make([]uint64, 0)
report := make([]MgrReport, 0)
if err := mysql.Db.Where("from_user_id = ?", userId).Find(&report).Error; err != nil && err != gorm.ErrRecordNotFound {
return nil, myerr.WrapErr(err)
}
for _, i := range report {
users = append(users, i.ToUserId)
}
return users, nil
}
package res_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type ResMicEmoji struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
IconUrl mysql.Str
SvagUrl mysql.Str
N mysql.Num
Status mysql.UserYesNo
}
//不可用
func (resMicEmoji *ResMicEmoji) Disable() *ResMicEmoji {
resMicEmoji.Status = mysql.NOUSER
return resMicEmoji
}
//上架
func (resMicEmoji *ResMicEmoji) Enable() *ResMicEmoji {
resMicEmoji.Status = mysql.USER
return resMicEmoji
}
func (resMicEmoji *ResMicEmoji) EditN(n uint32) *ResMicEmoji {
resMicEmoji.N = n
return resMicEmoji
}
func (resMicEmoji *ResMicEmoji) EditName(name string) *ResMicEmoji {
resMicEmoji.Name = name
return resMicEmoji
}
func (resMicEmoji *ResMicEmoji) EditIconUrl(iconUrl string) *ResMicEmoji {
resMicEmoji.IconUrl = iconUrl
return resMicEmoji
}
func (resMicEmoji *ResMicEmoji) EditSvagUrl(svagUrl string) *ResMicEmoji {
resMicEmoji.SvagUrl = svagUrl
return resMicEmoji
}
package task_m
import (
"hilo-group/domain/model"
"hilo-group/myerr"
)
func (taskUser *TaskUser) Persistent() error {
if err := model.Persistent(taskUser.Db, taskUser); err != nil {
return myerr.WrapErr(err)
}
return nil
}
func (taskUserDetail *TaskUserDetail) Persistent() error {
if err := model.Persistent(taskUserDetail.Db, taskUserDetail); err != nil {
return myerr.WrapErr(err)
}
return nil
}
\ No newline at end of file
package task_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/task_e"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"strconv"
"time"
)
type TaskConfig struct {
mysql.Entity
*domain.Model `gorm:"-"`
Name mysql.Str
Diamond mysql.Num
//任务类型
Type task_e.TypeTaskConfig
//频率类型
RateType task_e.RateTypeTaskConfig
//完成次数
FinishN mysql.Num
//排序
I mysql.Num
//奖励次数
AwardN mysql.Num
Status mysql.UserYesNo
}
type TaskUser struct {
mysql.Entity
*domain.Model `gorm:"-"`
TaskConfigId mysql.ID
UserId mysql.ID
DayStr mysql.Str
HasFinish mysql.YesNo
HasAward mysql.YesNo //整个完成奖励了
AwardN mysql.Num //获取奖励次数
FinishN mysql.Num
}
type TaskUserDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
TaskConfigId mysql.ID
UserId mysql.ID
TaskUserId mysql.ID
OriginId mysql.ID
}
func addTaskUserDetail(model *domain.Model, taskConfigId mysql.ID, userId mysql.ID, taskUserId mysql.ID, originId mysql.ID) error {
taskUserDetail := &TaskUserDetail{
Model: model,
TaskConfigId: taskConfigId,
UserId: userId,
TaskUserId: taskUserId,
OriginId: originId,
}
return taskUserDetail.Persistent()
}
func GetTaskUserOrErr(model *domain.Model, userId uint64, taskConfigId uint64) (*TaskUser, TaskConfig, error) {
//获取任务配置
taskConfig := TaskConfig{}
if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
Status: mysql.USER,
}).First(&taskConfig, taskConfigId).Error; err != nil {
return nil, TaskConfig{}, myerr.WrapErr(err)
}
//
paramTaskUser := TaskUser{
TaskConfigId: taskConfig.ID,
UserId: userId,
}
if taskConfig.RateType == task_e.Daily {
paramTaskUser.DayStr = time.Now().Format(utils.COMPACT_DATE_FORMAT)
}
//
taskUser := TaskUser{}
if err := model.Db.Model(&TaskUser{}).Where(&paramTaskUser).First(&taskUser).Error; err != nil {
return nil, TaskConfig{}, myerr.WrapErr(err)
}
taskUser.Model = model
//
return &taskUser, taskConfig, nil
}
func getTaskUserOrInit(model *domain.Model, userId uint64, taskConfig TaskConfig) (*TaskUser, error) {
//获取任务用户
taskUser := TaskUser{}
paramTaskUser := TaskUser{
TaskConfigId: taskConfig.ID,
UserId: userId,
}
if taskConfig.RateType == task_e.Daily {
paramTaskUser.DayStr = time.Now().Format(utils.COMPACT_DATE_FORMAT)
}
if err := model.Db.Model(&TaskUser{}).Where(&paramTaskUser).First(&taskUser).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &TaskUser{
Model: model,
TaskConfigId: taskConfig.ID,
UserId: userId,
DayStr: paramTaskUser.DayStr,
HasFinish: mysql.NO,
HasAward: mysql.NO,
FinishN: 0,
}, nil
} else {
return nil, myerr.WrapErr(err)
}
}
taskUser.Model = model
return &taskUser, nil
}
// 次数加1
func (taskUser *TaskUser) addFinishN(taskConfig TaskConfig) bool {
//没有使用sql悲观锁,update set where,第一:观察业务,都是用户自动触发,有时间性 第二:验证业务这样写,被投诉的概率,以证明此场景业务。
if taskUser.HasFinish == mysql.YES {
return false
} else {
taskUser.FinishN = taskUser.FinishN + 1
if taskUser.FinishN >= taskConfig.FinishN {
taskUser.HasFinish = mysql.YES
}
return true
}
}
// 次数覆盖
func (taskUser *TaskUser) beFinishN(taskConfig TaskConfig, finishN uint32) bool {
//没有使用sql悲观锁,update set where,第一:观察业务,都是用户自动触发,有时间性 第二:验证业务这样写,被投诉的概率,以证明此场景业务。
if taskUser.HasFinish == mysql.YES {
return false
} else {
taskUser.FinishN = finishN
if taskUser.FinishN >= taskConfig.FinishN {
taskUser.HasFinish = mysql.YES
}
return true
}
}
func (taskUser *TaskUser) Award(taskConfig TaskConfig) error {
if taskUser.HasAward == mysql.YES {
return bizerr.TaskHasAward
}
taskUser.AwardN = taskUser.AwardN + 1
if taskUser.AwardN >= taskConfig.AwardN {
taskUser.HasAward = mysql.YES
}
taskUser.SetCheckUpdateCondition("has_award = " + strconv.Itoa(int(mysql.NO)))
return nil
}
func AddTaskUser(model *domain.Model, t task_e.TypeTaskConfig, userId uint64, orginId uint64) (mysql.ID, error) {
//获取任务配置
taskConfig := TaskConfig{}
if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
Type: t,
Status: mysql.USER,
}).First(&taskConfig).Error; err != nil {
return 0, myerr.WrapErr(err)
}
//
taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
if err != nil {
return 0, err
}
if taskUser.addFinishN(taskConfig) {
if err := taskUser.Persistent(); err != nil {
return 0, myerr.WrapErr(err)
}
return taskConfig.ID, addTaskUserDetail(taskUser.Model, taskConfig.ID, userId, taskUser.ID, orginId)
}
return taskConfig.ID, nil
}
// return true:已经完成 false:未完成
func isTaskUserFinish(model *domain.Model, t task_e.TypeTaskConfig, userId uint64) (bool, error) {
//获取任务配置
taskConfig := TaskConfig{}
if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
Type: t,
Status: mysql.USER,
}).First(&taskConfig).Error; err != nil {
return false, myerr.WrapErr(err)
}
//
taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
if err != nil {
return false, err
}
return taskUser.HasFinish == mysql.YES, nil
}
func addTaskUserFinishN(model *domain.Model, t task_e.TypeTaskConfig, userId uint64, finishN uint32) error {
//获取任务配置
taskConfig := TaskConfig{}
if err := model.Db.Model(&TaskConfig{}).Where(&TaskConfig{
Type: t,
Status: mysql.USER,
}).First(&taskConfig).Error; err != nil {
return myerr.WrapErr(err)
}
//
taskUser, err := getTaskUserOrInit(model, userId, taskConfig)
if err != nil {
return err
}
if taskUser.beFinishN(taskConfig, finishN) {
if err := taskUser.Persistent(); err != nil {
return myerr.WrapErr(err)
}
return addTaskUserDetail(taskUser.Model, taskConfig.ID, userId, taskUser.ID, 0)
}
return nil
}
\ No newline at end of file
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
)
//腾讯云的拉黑名单,临时表
type UserBlackTencentyunTmp struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserExternal mysql.Str
BlockExternal mysql.Str
}
//黑名单
type UserBlock struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
BlockUserId mysql.ID
}
func initUserBlock(model *domain.Model, userId mysql.ID) *UserBlock {
return &UserBlock{
Model: model,
UserId: userId,
}
}
//拉黑
func (ub *UserBlock) block(blockUserId mysql.ID) (*UserBlock, error) {
err := ub.Db.Where(&UserBlock{
UserId: ub.UserId,
BlockUserId: blockUserId,
}).First(ub).Error
//已经拉黑了
if err == nil {
ub.SetLasyLoad()
return ub, nil
//return nil, myerr.NewWaring("已经标记拉黑")
} else if err == gorm.ErrRecordNotFound {
ub.BlockUserId = blockUserId
return ub, nil
} else {
return nil, myerr.WrapErr(err)
}
}
//取消拉黑
func (ub *UserBlock) blockCancel(blockUserId mysql.ID) (*UserBlock, error) {
err := ub.Db.Where(&UserBlock{
UserId: ub.UserId,
BlockUserId: blockUserId,
}).First(ub).Error
//
if err == nil {
ub.SetDel()
return ub, nil
} else if err == gorm.ErrRecordNotFound {
return nil, myerr.NewWaring("没有拉黑的记录")
} else {
return nil, myerr.WrapErr(err)
}
}
//检查是否存在拉黑
/*func CheckBlock(model *domain.Model, userId mysql.ID, blockUserId mysql.ID) (bool, error) {
var n int64
if err := model.Db.Model(&UserBlock{}).Where(&UserBlock{
UserId: userId,
BlockUserId: blockUserId,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
return n > 0, nil
}*/
//检查是否存在拉黑(无论是我拉黑别人,还是别人拉黑我), true:拉黑, false:不拉黑
func CheckBlockOr(model *domain.Model, userId mysql.ID, blockUserId mysql.ID) (bool, error) {
var n int64
if err := model.Db.Model(&UserBlock{}).Where(&UserBlock{
UserId: userId,
BlockUserId: blockUserId,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
if n == 0 {
if err := model.Db.Model(&UserBlock{}).Where(&UserBlock{
BlockUserId: userId,
UserId: blockUserId,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
}
return n > 0, nil
}
func CheckBlock(model *domain.Model, userId mysql.ID, blockUserId mysql.ID) (bool, error) {
var n int64
if err := model.Db.WithContext(model).Model(&UserBlock{}).Where(&UserBlock{
UserId: userId,
BlockUserId: blockUserId,
}).Count(&n).Error; err != nil {
return false, myerr.WrapErr(err)
}
return n > 0, nil
}
//检查互相拉黑的成员
func FilterBlock(model *domain.Model, userId mysql.ID, otherUserIds []mysql.ID) ([]mysql.ID, error) {
if len(otherUserIds) == 0 {
return otherUserIds, nil
}
userBlocks1 := []UserBlock{}
if err := model.Db.Model(&UserBlock{}).Where(&UserBlock{
UserId: userId,
}).Where("block_user_id in (?)", otherUserIds).Find(&userBlocks1).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userBlocks2 := []UserBlock{}
if err := model.Db.Model(&UserBlock{}).Where(&UserBlock{
BlockUserId: userId,
}).Where("user_id in (?)", otherUserIds).Find(&userBlocks2).Error; err != nil {
return nil, myerr.WrapErr(err)
}
blockSet := map[uint64]struct{}{}
for i, _ := range userBlocks1 {
blockSet[userBlocks1[i].BlockUserId] = struct{}{}
}
for i, _ := range userBlocks2 {
blockSet[userBlocks2[i].UserId] = struct{}{}
}
//
resultUserIds := make([]mysql.ID, 0, len(otherUserIds))
for i, r := range otherUserIds {
if _, flag := blockSet[r]; !flag {
resultUserIds = append(resultUserIds, otherUserIds[i])
}
}
return resultUserIds, nil
}
// 获取用户拉黑的用户ids
func GetBlockUserIds(model *domain.Model, userId mysql.ID) ([]mysql.ID, error) {
var userBlocks []UserBlock
if err := model.Db.Where(&UserBlock{
UserId: userId,
}).Find(&userBlocks).Error; err != nil {
return nil, myerr.WrapErr(err)
}
var userIds []mysql.ID
for _, v := range userBlocks {
userIds = append(userIds, v.BlockUserId)
}
return userIds, nil
}
\ No newline at end of file
package event_s
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/_const/enum/task_e"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/event/group_power_ev"
"hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/groupPower_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/msg_m"
"hilo-group/domain/model/task_m"
"hilo-group/domain/model/user_m"
"hilo-group/myerr"
"strconv"
"time"
)
func EventInit() {
GroupPowerEvents()
GroupSupportEvents()
GroupEvents()
GroupImMass()
GroupTheme()
}
func GroupSupportEvents() {
......@@ -144,3 +156,240 @@ func GroupPowerEvents() {
return nil
})
}
func GroupEvents() {
// 进房事件
group_ev.AddGroupInAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupInEvent)
if !ok {
model.Log.Errorf("AddGroupInAsync for room: %+v", event)
return nil
}
model.Log.Infof("AddGroupInAsync for room: %+v", event)
uer := group_m.UserEnterRoom{
UserId: event.UserId,
GroupId: event.GroupId,
EnterTime: time.Now(),
}
err := uer.Save(model.Db)
model.Log.Infof("AddGroupInAsync, UserEnterRoom err: %v", err)
return err
})
// 进入房间时,
group_ev.AddGroupInAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupInEvent)
if !ok {
model.Log.Errorf("AddGroupInAsync for room: %+v", event)
return nil
}
model.Log.Infof("AddGroupInAsync for user: %+v", event)
user, err := user_m.GetUser(model, event.UserId)
if err != nil {
return err
}
medals, err := user_m.GetUserMedalMerge(model.Log, model.Db, event.UserId)
if err != nil {
model.Log.Errorf("tim_m user AddGroupInAsync GetUserMedal err:%v, userId:%v", err, event.UserId)
return err
}
wealthGrade, _, err := user_m.GetWealthGrade(model, event.UserId)
if err != nil {
return err
}
charmGrade, _, err := user_m.GetCharmGrade(model, event.UserId)
if err != nil {
return err
}
if err = FlushGrades(event.ExternalId, wealthGrade, charmGrade); err != nil {
model.Log.Info("AddGroupInAsync, FlushGrades failed: ", err)
}
_, powerName, err := groupPower_m.GetUserGroupPower(model, event.UserId)
if err != nil {
return err
}
if err = FlushHiloInfo(user.ExternalId, event.IsVip, user.Code != user.OriginCode, medals, powerName, event.NobleLevel); err != nil {
model.Log.Info("AddGroupInAsync, FlushHiloInfo failed: ", err)
}
return nil
})
//被踢出
group_ev.AddGroupKickOutAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupKickOutEvent)
if !ok {
model.Log.Errorf("AddGroupKickOutAsync fail data")
return nil
}
model.Log.Infof("publicScreenMsg AddGroupKickOutAsync GroupId:%v, OperatorExternalId:%v, MemberExternalId:%v", event.GroupId, event.OperatorExternalId, event.MemberExternalId)
groupKickOutMsg := group_m.CommonPublicMsg{
Type: group_e.UserKickPublicScreenMsg,
OperatorExternalId: event.OperatorExternalId,
OperatorNick: event.OperatorName,
OperatorAvatar: event.OperatorFaceUrl,
ExternalId: event.MemberExternalId,
Nick: event.MemberName,
Avatar: event.MemberAvatar,
}
//
body, err := json.Marshal(groupKickOutMsg)
if err != nil {
return myerr.WrapErr(err)
}
txGroupId, err := group_m.ToTxGroupId(model, event.GroupId)
if err != nil {
return err
}
//发送公屏消息,
u, err := tencentyun.SendCustomMsg(model.Log, txGroupId, nil, string(body), "")
model.Log.Infof("publicScreenMsg AddGroupKickOutAsync result response.MsgSeq:%v, err:%v", u, err)
return err
})
}
func GroupImMass() {
//支付群主群发IM
group_ev.AddGroupImMassSync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupImMassEvent)
if !ok {
model.Log.Errorf("AddGroupImMassSync data fail")
return nil
}
model.Log.Infof("diamond AddGroupImMass groupId:%v userId:%v", event.GroupId, event.UserId)
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, event.UserId)
if err != nil {
return err
}
diamondAccountDetail, err := diamondAccount.GroupImMass()
if err != nil {
return err
}
return diamondAccountDetail.Persistent()
})
// 任务
group_ev.AddGroupImMassAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupImMassEvent)
if !ok {
model.Log.Errorf("AddGroupImMassSync data fail")
return nil
}
model.Log.Infof("task AddGroupImMassAsync %+v", event)
_, err := task_m.AddTaskUser(model, task_e.GroupImMass, event.UserId, 0)
return err
})
// 麦上的人/管理员群发消息,弹窗 fixme:放在这里已经不合适了
group_ev.AddGroupImMassAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupImMassEvent)
if !ok {
model.Log.Errorf("AddGroupImMassSync data fail")
return nil
}
model.Log.Infof("AddGroupImMassAsync begin groupId = %s, userId %d, members: %v, content: %s",
event.GroupId, event.UserId, event.Members, event.Content)
flag, err := group_m.IsHiddenGroup(model.Db, event.GroupId)
if err != nil {
return err
}
if flag {
model.Log.Infof("AddGroupImMassAsync, skip hidden group %s", event.GroupId)
return nil
}
if len(event.Members) <= 0 {
return nil
}
user, err := user_m.GetUser(model, event.UserId)
if err != nil {
return err
}
//过滤用户黑名单,只要单方面拉黑就不发
memberUserIds, err := user_m.FilterBlock(model, event.UserId, event.Members)
if err != nil {
return err
}
groupInfo, err := group_m.GetGroupInfo(model, event.GroupId)
if err != nil {
return err
}
userInCount, err := group_m.GetRoomVisitCount(event.GroupId)
if err != nil {
return err
}
if userInCount < 0 {
userInCount = 0
}
// 注意发消息使用了TxGroupId
err = rpc.SendGroupChatNotice(event.UserId, memberUserIds, user.ExternalId, user.Code, uint32(user.Sex), user.Avatar,
event.Content, groupInfo.TxGroupId, groupInfo.Name, groupInfo.Code, groupInfo.FaceUrl, uint32(userInCount))
model.Log.Infof("AddGroupImMassAsync, groupId = %s ended, err = %v", event.GroupId, err)
return nil
})
}
func GroupTheme() {
//购买自定义主题
group_ev.AddBuyGroupCustomThemeSync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.BuyGroupCustomThemeEvent)
if !ok {
model.Log.Errorf("AddBuyGroupCustomThemeSync data fail")
return nil
}
model.Log.Infof("diamond AddBuyGroupCustomTheme userId:%v, GroupCustomThemeId:%v", event.UserId, event.GroupCustomThemeId)
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, event.UserId)
if err != nil {
return err
}
diamondAccountDetail, err := diamondAccount.BuyGroupCustomTheme(event.GroupCustomThemeId)
if err != nil {
return err
}
if err := diamondAccountDetail.Persistent(); err != nil {
return err
}
return nil
})
}
func FlushGrades(userExtId string, wealthGrade uint32, charmGrade uint32) error {
level := (charmGrade & 0x000000FF << 8) | wealthGrade&0x000000FF
return tencentyun.SetUserLevel(userExtId, level)
}
type TimHiloInfo struct {
IsVip bool `json:"isVip"`
IsPretty bool `json:"isPretty"`
Medals []uint32 `json:"medals"`
PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称
NobleLevel uint16 `json:"nobleLevel"`
}
func FlushHiloInfo(extId string, isVip bool, isPrettyCode bool, medals []uint32, groupPowerName string, nobleLevel uint16) error {
info := TimHiloInfo{IsVip: isVip, IsPretty: isPrettyCode, Medals: medals, PowerName: groupPowerName, NobleLevel: nobleLevel}
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
package group_mic_s
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/redisCli"
uuid "github.com/satori/go.uuid"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/model/group_m"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"time"
)
type GroupMicService struct {
svc *domain.Service
}
func NewGroupPowerService(myContext *mycontext.MyContext) *GroupMicService {
svc := domain.CreateService(myContext)
return &GroupMicService{svc}
}
//修改群组中麦的数量
func (s *GroupMicService) GroupMicNumChange(groupId string, userId uint64, micNumType group_e.GroupMicNumType, micOn bool) error {
model := domain.CreateModelContext(s.svc.MyContext)
//数据库修改群组麦的数量
//检查权限
if err := group_m.CheckPermission(model, groupId, userId); err != nil {
return err
}
//删除麦位数量类型缓存
group_m.InitMicNumType(model, groupId, micNumType).ClearCache()
//
groupInfo, _ := group_m.GetGroupInfo(model, groupId)
if groupInfo == nil {
return bizerr.GroupNotFound
}
//判断数据是否发生了变化
//关闭麦位
if micOn == false {
if groupInfo.MicOn == micOn {
return nil
}
} else {
if groupInfo.MicOn == micOn && groupInfo.MicNumType == micNumType {
return nil
}
}
//修改数据,然后数据持久化,
g := group_m.GroupInfo{
MicOn: micOn,
}
fields := []string{"mic_on"}
//开启麦位才修改micNumType
returnMicNumType := g.MicNumType
if micOn == true {
g.MicNumType = micNumType
fields = append(fields, "mic_num_type")
returnMicNumType = micNumType
}
db := g.Update(model, groupId, fields)
if db.Error != nil {
return myerr.WrapErr(db.Error)
}
//增加麦位数量类型缓存
group_m.InitMicNumType(model, groupId, micNumType).AddCache()
//麦位上的信息,清理
group_m.ClearMic(groupId)
type Content struct {
MicOn bool `json:"micOn"`
MicNumType group_e.GroupMicNumType `json:"micNumType"`
Timestamp int64 `json:"timestamp"`
}
r := Content{
MicOn: micOn,
MicNumType: returnMicNumType,
Timestamp: time.Now().Unix(),
}
buf, err := json.Marshal(r)
if err != nil {
model.Log.Errorf("GroupMicNumChange Content json.Marshal err:%v", err)
}
// 发信令,让前端重新拉取,接受容错,
signal_s.SendSignalMsg(model, groupId, group_m.GroupSystemMsg{
MsgId: group_e.GroupMicChangeSignal,
Content: string(buf),
}, false)
group_m.MicNumChangeRPush(model, groupId, returnMicNumType, micOn)
return nil
}
//加锁, sign作为密钥存在(预防被别人删除,比如:先者删除了后者的锁),
func redisLock(key string, sign string, expiration time.Duration, callBack func() error) error {
flag, err := redisCli.GetRedis().SetNX(context.Background(), key, sign, expiration).Result()
if err != nil {
return myerr.WrapErr(err)
}
if flag {
err = callBack()
redisSign, _ := redisCli.GetRedis().Get(context.Background(), key).Result()
if redisSign == sign {
redisCli.GetRedis().Del(context.Background(), key)
}
return err
} else {
return bizerr.GroupConcurrencyLock
}
}
//加入麦位,锁两秒
func (s *GroupMicService) GroupMicIn(groupUuid string, i int, userId uint64, externalId string) error {
return redisLock(redis_key.GetPrefixGroupMicUserInLock(userId), uuid.NewV4().String(), time.Second*2, func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
mic, err := group_m.GetMic(model, groupUuid, i)
if err != nil {
return err
}
return mic.In(userId, externalId)
})
}
//离开麦位
func (s *GroupMicService) GroupMicLeave(groupUuid string, i int, userId uint64, externalId string) error {
return redisLock(redis_key.GetPrefixGroupMicUserDelLock(groupUuid, i), uuid.NewV4().String(), time.Second*2, func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
micUser, err := group_m.GetMicUser(model, groupUuid, i)
if err != nil {
return err
}
if micUser != nil {
return micUser.LeaveByUser(userId, externalId)
}
return nil
})
}
//邀请上麦,锁两秒
func (s *GroupMicService) GroupMicInvite(groupUuid string, operateUserId uint64, beInvitedExternalId string) error {
model := domain.CreateModelContext(s.svc.MyContext)
if err := group_m.InviteMicIn(model, groupUuid, operateUserId, beInvitedExternalId); err != nil {
return err
}
return nil
}
//麦位加锁,
func (s *GroupMicService) GroupMicLock(userId uint64, externalId string, groupUuid string, i int) error {
//后果等级不高,不需要加锁
model := domain.CreateModelContext(s.svc.MyContext)
mic, err := group_m.GetMic(model, groupUuid, i)
if err != nil {
return err
}
return mic.MgrLock(userId, externalId)
}
//麦位解锁
func (s *GroupMicService) GroupMicUnLock(userId uint64, externalId string, groupUuid string, i int) error {
//后果等级不高,不需要加锁
model := domain.CreateModelContext(s.svc.MyContext)
mic, err := group_m.GetMic(model, groupUuid, i)
if err != nil {
return err
}
return mic.MgrUnLock(userId, externalId)
}
// 麦位静音
func (s *GroupMicService) GroupMicMute(userId uint64, externalId string, groupUuid string, i int) error {
//后果等级不高,不需要加锁
model := domain.CreateModelContext(s.svc.MyContext)
mic, err := group_m.GetMic(model, groupUuid, i)
if err != nil {
return err
}
return mic.MgrMute(userId, externalId)
}
// 麦位解除静音
func (s *GroupMicService) GroupMicUnMute(userId uint64, externalId string, groupUuid string, i int) error {
//后果等级不高,不需要加锁
model := domain.CreateModelContext(s.svc.MyContext)
mic, err := group_m.GetMic(model, groupUuid, i)
if err != nil {
return err
}
return mic.MgrUnMute(userId, externalId)
}
//开启麦
func (s *GroupMicService) GroupMicSpeechOpen(userId uint64, externalId string, groupUuid string, i int) error {
//自己/管理人开启禁麦,并发率不高,后果等级不高
model := domain.CreateModelContext(s.svc.MyContext)
micUser, err := group_m.GetMicUser(model, groupUuid, i)
if err != nil {
return err
}
return micUser.SpeechOpen(userId, externalId)
}
//关闭麦
func (s *GroupMicService) GroupMicSpeechClose(userId uint64, externalId string, groupUuid string, i int) error {
model := domain.CreateModelContext(s.svc.MyContext)
micUser, err := group_m.GetMicUser(model, groupUuid, i)
if err != nil {
return err
}
return micUser.SpeechClose(userId, externalId)
}
//麦上的人群发消息
func (s *GroupMicService) GroupIMMassByInMic(groupId string, userId uint64, externalId string, content string) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
micUser, err := group_m.GetMicUserByExternalId(model, externalId)
if err != nil {
return err
}
if err := micUser.ImMass(externalId); err != nil {
return err
}
//校验群组ID
if micUser.GroupUuid != groupId {
return myerr.NewSysError("groupId 不一致, http:groupId <> micUser.groupId")
}
//获取群成员
gm, err := group_m.GetMembers(model.Db, groupId)
if err != nil {
return err
}
uids := make([]uint64, 0)
for _, i := range gm {
//排除自己
if userId != i.UserId {
uids = append(uids, i.UserId)
}
}
return group_ev.PublishGroupImMass(model, &group_ev.GroupImMassEvent{
GroupId: groupId,
UserId: userId,
Members: uids,
Content: content,
})
})
}
// 群管理人群发消息
func (s *GroupMicService) GroupIMMassByMgr(groupId string, userId uint64, externalId string, content string) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
//检查权限
if err := group_m.CheckPermission(model, groupId, userId); err != nil {
return err
}
//获取群成员
gm, err := group_m.GetMembers(model.Db, groupId)
if err != nil {
return err
}
uids := make([]uint64, 0)
for _, i := range gm {
//排除自己
if userId != i.UserId {
uids = append(uids, i.UserId)
}
}
return group_ev.PublishGroupImMass(model, &group_ev.GroupImMassEvent{
GroupId: groupId,
UserId: userId,
Members: uids,
Content: content,
})
})
}
package group_s
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/mgr_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/mgr_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"strconv"
"time"
)
......@@ -116,3 +123,169 @@ func (s *GroupService) GetJoinGroupLimit(userId mysql.ID) (uint, error) {
}
return maxJoin, nil
}
//更新用户在群上的消息状态
func (s *GroupService) GroupUserMsgStatus(userId uint64, groupUuid string, msgStatus group_e.MsgStatusGroupUser) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
//var groupInfo group_m.GroupInfo
//if err := model.Db.Where(&group_m.GroupInfo{
// ImGroupId: groupUuid,
//}).First(&groupInfo).Error; err != nil {
// return nil, nil, myerr.WrapErr(err)
//}
//
groupUser, err := group_m.GetGroupUserOrInit(model, groupUuid, userId)
if err != nil {
return err
}
if msgStatus == group_e.NormalMsgStatusGroupUser {
groupUser.MsgStatusNormal()
} else if msgStatus == group_e.MuteMsgStatusGroupUser {
groupUser.MsgStatusMute()
} else if msgStatus == group_e.DoNotDisturbMsgStatusGroupUser {
groupUser.MsgStatusDoNotDisturb()
}
return groupUser.Persistent()
})
}
//举报群组
func (s *GroupService) ReportGroup(fromUserId mysql.ID, groupId mysql.Str, reasonType mgr_e.ReportReasonType, imageUrl mysql.Str, reason mysql.Str) error {
return s.svc.Transactional(func() error {
model := domain.CreateModelContext(s.svc.MyContext)
reportGroup := mgr_m.ReportGroupAdd(model, fromUserId, groupId, reasonType, imageUrl, reason)
err := reportGroup.Persistent()
if err != nil {
return err
}
return nil
})
}
//群组自定义主题修改
func (s *GroupService) GroupCustomThemeUsing(userId mysql.ID, externalId string, imGroupId string, groupCustomThemeId uint64) error {
err1 := s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
groupCustomTheme, err := group_m.GetGroupCustomThemeById(model, imGroupId, groupCustomThemeId)
if err != nil {
return err
}
groupCustomTheme, err = groupCustomTheme.SetUsing(userId)
if err != nil {
return err
}
if err := groupCustomTheme.Persistent(); err != nil {
return err
}
//修改数据,然后数据持久化,
g := group_m.GroupInfo{
ThemeId: 0,
}
fields := []string{"theme_id"}
db := g.Update(model, imGroupId, fields)
if db.Error != nil {
return myerr.WrapErr(db.Error)
}
if err := groupCustomTheme.Persistent(); err != nil {
return err
} else {
return nil
}
})
if err1 == nil {
type signalMsg struct {
Name string `json:"name"`
Introduction string `json:"introduction"`
Notification string `json:"notification"`
FaceUrl string `json:"faceUrl"`
MicOn bool `json:"micOn"`
MicNumType group_e.GroupMicNumType
ThemeId uint64 `json:"themeId"`
ThemeUrl string `json:"themeUrl"`
//1: 官方 2:自定义
ThemeType uint8 `json:"themeType"`
}
model := domain.CreateModelContext(s.svc.MyContext)
groupInfo, err := group_m.GetGroupInfo(model, imGroupId)
if err != nil {
model.Log.Error(err)
return nil
}
signal := signalMsg{
Name: groupInfo.Name,
Introduction: groupInfo.Introduction,
Notification: groupInfo.Notification,
FaceUrl: groupInfo.FaceUrl,
MicOn: groupInfo.MicOn,
MicNumType: groupInfo.MicNumType,
ThemeId: 0,
ThemeUrl: "",
ThemeType: 0,
}
if groupInfo.ThemeId != 0 {
//signal.ThemeId = groupInfo.ThemeId
signal.ThemeType = 1
if rows, err := res_m.GroupThemeGetAllInUse(model.Db); err == nil {
for _, i := range rows {
if i.ID == uint64(groupInfo.ThemeId) {
signal.ThemeId = i.ID
signal.ThemeUrl = i.Url
break
}
}
}
} else {
//可能是自定义主题
id, url, err := group_m.GetShowCustomTheme(model, imGroupId)
if err != nil {
model.Log.Error(err)
return nil
}
if id > 0 {
signal.ThemeId = id
signal.ThemeUrl = url
signal.ThemeType = 2
}
}
buf, err := json.Marshal(signal)
if err == nil {
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupEditProfileSignal, Source: externalId, Content: string(buf)}
signal_s.SendSignalMsg(model, imGroupId, systemMsg, false)
}
}
return err1
}
//增加群组自定义主题
func (s *GroupService) AddGroupCustomTheme(userId mysql.ID, imGroupId string, picUrl string) (uint64, string, error) {
var themeId uint64 = 0
var themeUrl string = ""
return themeId, themeUrl, s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
groupCustomTheme, err := group_m.AddGroupCustomTheme(model, userId, imGroupId, picUrl)
if err != nil {
return err
}
//将group_info的theme_id设置为0
//修改数据,然后数据持久化,
g := group_m.GroupInfo{
ThemeId: 0,
}
fields := []string{"theme_id"}
db := g.Update(model, imGroupId, fields)
if db.Error != nil {
return myerr.WrapErr(db.Error)
}
if err := groupCustomTheme.Persistent(); err != nil {
return err
}
themeId = groupCustomTheme.ID
themeUrl = groupCustomTheme.PicUrl
return group_ev.PublishBuyGroupCustomTheme(model, &group_ev.BuyGroupCustomThemeEvent{
GroupCustomThemeId: groupCustomTheme.ID,
UserId: userId,
})
})
}
package group_s
import (
"context"
"encoding/json"
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/agora"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key"
"hilo-group/cv/property_cv"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/cache/tim_c"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"strconv"
"time"
)
// 创建群组
......@@ -92,3 +113,333 @@ func (s *GroupService) LeaveGroupMember(model *domain.Model, groupId string, use
return nil
}
//进入房间, 返回channelId, err
func (s *GroupService) GroupIn(userId uint64, externalId string, groupUuid string, password, imei, ip string) (string, string, error) {
var channelId string
var token string
err := s.svc.Transactional(func() error {
//检查群组是否存在, 没有真正的domel,直接service上怼
model := domain.CreateModel(s.svc.CtxAndDb)
// 群是否被封禁
banned := group_m.GroupBanned{ImGroupId: groupUuid}
if err := banned.Get(model); err != gorm.ErrRecordNotFound {
return bizerr.GroupIsBanned
}
var groupInfo group_m.GroupInfo
if err := model.Db.Where(&group_m.GroupInfo{
ImGroupId: groupUuid,
}).First(&groupInfo).Error; err != nil {
return myerr.WrapErr(err)
}
if userId != groupInfo.Owner && len(groupInfo.Password) > 0 && password != groupInfo.Password {
return bizerr.IncorrectPassword
}
//检查群组中是否有拉黑名单
//var n int64
//if err := model.Db.Model(&group_m.GroupBlacklist{}).Where(&group_m.GroupBlacklist{
// ImGroupId: groupUuid,
// UserId: userId,
//}).Count(&n).Error; err != nil {
// return nil, nil, myerr.WrapErr(err)
//}
//if n != 0 {
// return nil, nil, bizerr.InBlacklist
//}
svip, _ := rpc.GetUserSvip(model, userId)
if userId != groupInfo.Owner {
// 是否超管
isM, err := user_m.IsSuperManager(model, userId)
if err != nil {
model.Log.Errorf("GroupIn err:%v", err)
return myerr.NewSysError("not super manager")
}
// 不是超管 且 用户是否在群的黑名单中
if !isM && group_m.InGroupBlackList(model, groupUuid, imei, ip, userId) {
if svip.SvipLevel < 6 { // svip6暂时不判断GroupBlackList
return bizerr.InBlacklist
}
}
}
//是否被踢出
if i, err := redisCli.GetRedis().Exists(context.Background(), redis_key.GetGroupKickGroupUuidUserId(groupUuid, userId)).Result(); err != nil {
return myerr.WrapErr(err)
} else if i == 0 {
user, err := user_m.GetUser(model, userId)
if err != nil {
return err
}
channelId, token, err = agora.CreateGroupAgora(groupInfo.ChannelId, uint32(userId))
if err != nil {
return err
} else {
//加入房间
group_m.RoomLivingIn(model, groupUuid, userId, externalId, false)
groupUser, err := group_m.GetGroupUserOrInit(model, groupUuid, userId)
if err != nil {
model.Log.Errorf("GroupIn GetGroupUserOrInit err:%v, groupId:%v, userId:%v", err, groupUuid, userId)
}
if err := groupUser.SetRoomInTime().Persistent(); err != nil {
model.Log.Errorf("GroupIn groupUser Persistent err:%v, groupId:%v, userId:%v", err, groupUuid, userId)
}
// 发送进群TIM信令。fixme: 应该发在event处理
isVip, err := user.CheckVip()
if err != nil {
return err
}
nobleLevel, err := noble_m.GetNobleLevel(mysql.Db, userId)
if err != nil {
return err
}
type UserParam struct {
Nick string `json:"nick"`
UserAvatar string `json:"userAvatar"`
IsVip bool `json:"isVip"`
RideId uint64 `json:"rideId"`
RideUrl string `json:"rideUrl"`
RideEffectUrl string `json:"rideEffectUrl"`
RidSenderAvatar string `json:"ridSenderAvatar"`
RidReceiverAvatar string `json:"ridReceiverAvatar"`
NobleLevel uint16 `json:"nobleLevel"`
SvipLevel int `json:"svipLevel"`
Svip rpc.CvSvip `json:"svip"`
}
up := user_m.UserProperty{}
rides, err := up.BatchGet(mysql.Db, []uint64{userId})
if err != nil {
return err
}
//rp := res_m.ResProperty{}
//properties, err := rp.GetAll(mysql.Db)
properties, err := property_cv.GetExtendedProperty(mysql.Db)
if err != nil {
return err
}
r := UserParam{
Nick: user.Nick,
UserAvatar: user.Avatar,
IsVip: isVip,
RideId: rides[userId],
RideUrl: properties[rides[userId]].PicUrl,
RideEffectUrl: properties[rides[userId]].EffectUrl, // todo replace ui svga
RidSenderAvatar: properties[rides[userId]].SenderAvatar,
RidReceiverAvatar: properties[rides[userId]].ReceiverAvatar,
NobleLevel: nobleLevel,
Svip: rpc.CopySimpleSvip(svip),
}
buf, err := json.Marshal(r)
if err == nil {
//发送腾讯云IM系统消息
signal_s.SendSignalMsg(model,
groupUuid, group_m.GroupSystemMsg{
MsgId: group_e.GroupInSignal,
Source: user.ExternalId,
Content: string(buf),
}, true)
}
isMember, _ := group_m.IsGroupMember(model.Db, groupUuid, userId)
return group_ev.PublishGroupIn(model, &group_ev.GroupInEvent{
GroupId: groupUuid,
UserId: userId,
ExternalId: user.ExternalId,
Nick: user.Nick,
Avatar: user.Avatar,
IsMember: isMember,
IsVip: isVip,
NobleLevel: nobleLevel,
})
}
} else {
return bizerr.GroupInKick
}
})
if err != nil {
return "", "", err
} else {
return channelId, token, nil
}
}
func (s *GroupService) JoinGroup(userId uint64, externalId string, groupId string) error {
model := domain.CreateModel(s.svc.CtxAndDb)
model.Log.Infof("Async: user %d(%s) is joining group %s", userId, externalId, groupId)
for i := 1; i < 3; i++ {
info, err, errCode := tencentyun.AddGroup(model, groupId, []string{externalId})
if err == nil && info != nil {
for i, r := range info {
if i == externalId {
if r == group_e.ADD_GROUP_DONE || r == group_e.ADD_GROUP_DUPLICATE {
// 加群成功后,马上发送通知给客户端,让他们拉取历史消息
err = rpc.SendJoinGroup(userId, externalId, groupId)
model.Log.Infof("joinGroup: SendJoinGroup err = %v", err)
}
if r == group_e.ADD_GROUP_DONE {
group_c.ClearGroupMemberCount(groupId)
tim_c.AddGroupMember(model, groupId, externalId)
}
}
return nil
}
} else if errCode == 10014 || errCode == 10038 {
// 如果群成员达到上限,删除一个(10014 达到群上限;10038 达到APP上限)
extId, err := s.RemoveZombie(model, groupId)
if err != nil {
return err
}
model.Log.Infof("JoinGroup %s limit reached, errCode = %d, %s kicked", groupId, errCode, extId)
}
}
return fmt.Errorf("failed 3 times")
}
// 清除TIM群的僵尸
func (s *GroupService) RemoveZombie(model *domain.Model, groupId string) (string, error) {
rows, err := group_m.GetMembers(model.Db, groupId)
if err != nil {
return "", err
}
userIds := make([]uint64, 0)
for _, i := range rows {
userIds = append(userIds, i.UserId)
}
model.Log.Infof("JoinGroup %s: members: %v", groupId, userIds)
roomUids, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return "", err
}
model.Log.Infof("JoinGroup %s: roomUids: %v", groupId, roomUids)
userIds = append(userIds, roomUids...)
userIds = utils.UniqueSliceUInt64(userIds)
m, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return "", err
}
extIdsMap := make(map[string]uint64)
for _, i := range m {
extIdsMap[i.ExternalId] = i.ID
}
model.Log.Infof("JoinGroup %s: extIdsMap: %v", groupId, extIdsMap)
_, gm, err := tencentyun.GetGroupMemberInfo(model, groupId)
if err != nil {
return "", err
}
zombie := ""
for _, i := range gm {
if _, ok := extIdsMap[i.Member_Account]; !ok {
model.Log.Infof("JoinGroup %s: to kick %s", groupId, i.Member_Account)
tencentyun.LeaveGroup(groupId, []string{i.Member_Account})
zombie = i.Member_Account
break
}
}
return zombie, nil
}
//离开房间
func (s *GroupService) GroupLeave(userId uint64, externalId string, groupId string) error {
model := domain.CreateModelContext(s.svc.MyContext)
_, err := group_m.RoomLivingLeave(model, userId, externalId, groupId)
return err
}
//踢人
func (s *GroupService) GroupKick(groupUuid string, userId uint64, userExternalId string, userNick string, avatar string, beKickUserId uint64, beKickExternalId string, beKickUserNick string, beKickUserAvatar string) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
//木有model层给我,直接server怼了
//被踢的人不能是超级管理人
if flag, err := user_m.IsSuperManager(model, beKickUserId); err != nil {
return err
} else if flag {
return bizerr.OfficialStaffLimit
}
//超级管理人,无敌状态
if flag, err := user_m.IsSuperManager(model, userId); err != nil {
return err
} else if !flag {
//判断权限
if err := group_m.MgrPermission(model, groupUuid, userId, beKickUserId); err != nil {
return err
}
//检查是否是贵族
if flag, err := noble_m.CheckNobleLevel(model.Db, beKickUserId, 5); err != nil {
return err
} else if flag {
return bizerr.NobleNoKickLevel5
}
}
//踢人10分钟
_, err := redisCli.GetRedis().Set(context.Background(), redis_key.GetGroupKickGroupUuidUserId(groupUuid, beKickUserId), strconv.Itoa(int(beKickUserId)), time.Minute*10).Result()
if err != nil {
return myerr.WrapErr(err)
}
//删除房间中redis
//group_m.RoomLivingLeave(model, groupUuid, beKickUserId)
group_m.RoomLivingLeaveByKick(model, groupUuid, beKickUserId, beKickExternalId, userExternalId)
// 发信令,让前端重新拉取,接受容错,
/* SendSignalMsg(groupUuid, group_m.GroupSystemMsg{
MsgId: group_m2.GroupKickOut,
Source: userExternalId,
Target: beKickExternalId,
})*/
//记录踢人(非事务性, 错误不进行处理)
if err := group_m.AddGroupKickRecord(model, groupUuid, userId, beKickUserId); err != nil {
model.Log.Errorln(err)
}
/* //获取用户是否在麦上, 让用户离开麦
micUser, err := group_m.GetMicUserByExternalId(model, beKickExternalId)
if err != nil {
return nil, nil, err
}
if micUser != nil {
micUser.LeaveByUser(userId, userExternalId)
}*/
return group_ev.PublishGroupKickOut(model, &group_ev.GroupKickOutEvent{
GroupId: groupUuid,
OperatorExternalId: userExternalId,
OperatorName: userNick,
OperatorFaceUrl: avatar,
MemberExternalId: beKickExternalId,
MemberName: beKickUserNick,
MemberAvatar: beKickUserAvatar,
})
})
}
// 群管理人清理公屏
func (s *GroupService) GroupClearScreenByMgr(groupId string, userId uint64) error {
model := domain.CreateModelContext(s.svc.MyContext)
//检查权限
if err := group_m.CheckPermission(model, groupId, userId); err != nil {
return err
}
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupClearScreen, Source: "", Content: ""}
signal_s.SendSignalMsg(model, groupId, systemMsg, false)
return nil
}
......@@ -37,19 +37,24 @@ var (
EditCd = myerr.NewBusinessCode(9017, "not allow to edit", myerr.BusinessData{}) // 编辑cd中
// 麦位
GroupMicNoPermission = myerr.NewBusinessCode(12000, "Mic has no permission to mic", myerr.BusinessData{}) // 麦位没有操作的权限
GroupMicNoUser = myerr.NewBusinessCode(12002, "No one on Mic", myerr.BusinessData{}) // 麦位上没有人
GroupMicLock = myerr.NewBusinessCode(12003, "Mic is locked", myerr.BusinessData{}) // 麦位加锁了
GroupMicHasUser = myerr.NewBusinessCode(12004, "Mic occupied", myerr.BusinessData{}) // 麦位中已经有人了
GroupMicUserHasIn = myerr.NewBusinessCode(12006, "Already on Mic", myerr.BusinessData{}) // 你已经在别的麦位上了
GroupMicNoYou = myerr.NewBusinessCode(12007, "Not on Mic", myerr.BusinessData{}) // 你不在该麦位上
GroupInfoMicClosed = myerr.NewBusinessCode(12009, "The Group does not open the mic positions", myerr.BusinessData{})
GroupMicNoPermission = myerr.NewBusinessCode(12000, "Mic has no permission to mic", myerr.BusinessData{}) // 麦位没有操作的权限
GroupMicNoUser = myerr.NewBusinessCode(12002, "No one on Mic", myerr.BusinessData{}) // 麦位上没有人
GroupMicLock = myerr.NewBusinessCode(12003, "Mic is locked", myerr.BusinessData{}) // 麦位加锁了
GroupMicHasUser = myerr.NewBusinessCode(12004, "Mic occupied", myerr.BusinessData{}) // 麦位中已经有人了
GroupConcurrencyLock = myerr.NewBusinessCode(12005, "concurrent Mic operation, please try ageain later", myerr.BusinessData{}) // 麦位并发操作,请重试
GroupMicUserHasIn = myerr.NewBusinessCode(12006, "Already on Mic", myerr.BusinessData{}) // 你已经在别的麦位上了
GroupMicNoYou = myerr.NewBusinessCode(12007, "Not on Mic", myerr.BusinessData{}) // 你不在该麦位上
GroupMicInByInviteFail = myerr.NewBusinessCode(12008, "从邀请中上麦失败", myerr.BusinessData{})
GroupInfoMicClosed = myerr.NewBusinessCode(12009, "The Group does not open the mic positions", myerr.BusinessData{})
GroupMicBanTourist = myerr.NewBusinessCode(12010, "Mic need member", myerr.BusinessData{}) // 游客不能上麦
// 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
NotGroupMember = myerr.NewBusinessCode(14002, "Not a group member", myerr.BusinessData{}) // 不是群成员
IncorrectPassword = myerr.NewBusinessCode(14003, "Incorrect password", myerr.BusinessData{}) // 密码错
NoPrivileges = myerr.NewBusinessCode(14004, "Not enough permission", myerr.BusinessData{}) // 操作权限不够
InBlacklist = myerr.NewBusinessCode(14005, "Can not join the group due to blacklist", myerr.BusinessData{}) // 在群黑名单中,不能进群
GroupInKick = myerr.NewBusinessCode(14007, "Kicked, can not join the group. Try again later", myerr.BusinessData{}) // 在被踢出的有效期中
OwnerCannotLeave = myerr.NewBusinessCode(14008, "Owner can not leave the group", myerr.BusinessData{}) // 群主不能退群
WrongPasswordLength = myerr.NewBusinessCode(14010, "Incorrect password length", myerr.BusinessData{}) // 密码长度错误
GroupIsBanned = myerr.NewBusinessCode(14011, "group is banned by ", myerr.BusinessData{}) // 群已经被管理员封禁
......@@ -73,8 +78,11 @@ var (
GroupPowerNoOwner = myerr.NewBusinessCode(15005, "power owner not exits or unique", myerr.BusinessData{}) // 国家势力主不存在或不唯一
GroupPowerStayTooShort = myerr.NewBusinessCode(15006, "You joined this power not more than 10 days ago", myerr.BusinessData{}) // 加入国家势力不超过10天
TaskHasAward = myerr.NewBusinessCode(19001, "task has award", myerr.BusinessData{})
//贵族
NobleNoMicSpeechCloseLevel5 = myerr.NewBusinessCode(21001, "Can't mute the King", myerr.BusinessData{}) //无法禁言贵族5
NobleNoKickLevel5 = myerr.NewBusinessCode(21002, "Can't kick the King", myerr.BusinessData{}) //无法禁言贵族5
// 超级管理人
OfficialStaffLimit = myerr.NewBusinessCode(22001, "Operation failed", myerr.BusinessData{})
......
package group_r
import (
"context"
"encoding/json"
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"gorm.io/gorm"
"hilo-group/_const/enum/game_e"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/mgr_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/_const/redis_key"
"hilo-group/cv/gift_cv"
"hilo-group/cv/group_cv"
"hilo-group/cv/group_power_cv"
"hilo-group/cv/medal_cv"
......@@ -20,6 +28,7 @@ import (
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/mgr_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m"
"hilo-group/domain/model/user_m"
......@@ -30,7 +39,9 @@ import (
"hilo-group/req"
"hilo-group/resp"
"sort"
"strconv"
"strings"
"time"
)
// @Tags 群组
......@@ -650,3 +661,617 @@ func GetGroupAdmin(c *gin.Context) (*mycontext.MyContext, error) {
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 修改群消息设置(默认,静音,免打扰)(obsolete)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param status formData string true "消息状态 0:默认 1:静音 2:免打扰"
// @Success 200
// @Router /v1/imGroup/user/msg/status [put]
func GroupUserMsg(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
status, err := strconv.ParseUint(c.PostForm("status"), 10, 64)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if err := group_s.NewGroupService(myContext).GroupUserMsgStatus(userId, groupId, mysql.Type(status)); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 举报
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param reasonType formData int false "投诉原因 1:语言骚扰(verbal harassment)2:Nudity 3:不良消息 4:不雅图片" Enums(1, 2, 3, 4)
// @Param imageUrl formData string false "证据图片url"
// @Param reason formData string false "投诉内容"
// @Success 200
// @Router /v1/imGroup/report [post]
func GroupReport(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
reasonTypeStr := c.PostForm("reasonType")
var reasonType uint64 = 0
if reasonTypeStr != "" {
reasonType, err = strconv.ParseUint(reasonTypeStr, 10, 64)
if err != nil {
return myContext, myerr.WrapErr(err)
}
}
imageUrl := c.PostForm("imageUrl")
reason := c.PostForm("reason")
if err = group_s.NewGroupService(myContext).ReportGroup(userId, groupId, mgr_e.ReportReasonType(reasonType), imageUrl, reason); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
type GroupBanner struct {
//h5链接
H5Url string `json:"h5Url"`
//图片地址
BannerUrl string `json:"bannerUrl"`
//群主Id
GroupId string `json:"groupId"`
}
// @Tags 群组
// @Summary banner列表
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} GroupBanner
// @Router /v1/imGroup/banner/list [get]
func GroupBannerList(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
var groupBanners []GroupBanner
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
mgrGroupBanners := []mgr_m.GroupBanner{}
if err := mysql.Db.Model(&mgr_m.GroupBanner{}).Where(&mgr_m.GroupBanner{
Status: mysql.YES,
}).Order("n desc").Find(&mgrGroupBanners).Error; err != nil {
return myContext, err
}
_deviceType, _ := c.Get(mycontext.DEVICETYPE)
_appVersion, _ := c.Get(mycontext.APP_VERSION)
model := domain.CreateModelNil()
deviceType, appVersion := cast.ToString(_deviceType), cast.ToString(_appVersion)
vc := version_m.GetVersionControlByPlatform(model, deviceType)
allow, err := utils.CompareVersion(appVersion, fmt.Sprintf("<= %s", vc.AuditVersion))
model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v", appVersion, vc.AuditVersion, allow, err)
// 获取国家信息
country, area, err := user_m.GetUserCountryArea(model, userId)
if err != nil {
model.Log.Errorf("GroupBannerList 获取国家资源错误 userId:%d, err:%v", userId, err)
return myContext, err
}
groupCodes := []string{}
for i := 0; i < len(mgrGroupBanners); i++ {
groupCodes = append(groupCodes, mgrGroupBanners[i].GroupCode)
}
groupMap := map[string]string{}
if len(groupCodes) > 0 {
var groupInfos []group_m.GroupInfo
if err := mysql.Db.Model(&group_m.GroupInfo{}).Where("code in (?) ", groupCodes).Find(&groupInfos).Error; err != nil {
return myContext, err
}
for i := 0; i < len(groupInfos); i++ {
groupMap[groupInfos[i].Code] = groupInfos[i].TxGroupId
}
}
nowUnix := time.Now().Unix()
for _, v := range mgrGroupBanners {
if !allow && v.Url == "https://h5.whoisamy.shop/action/hiloHtml/22_05_30_recharge/topup.html" {
model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v,skip top recharge", appVersion, vc.AuditVersion, allow, err)
continue
}
if !allow && v.ID == 2301 {
model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v,skip top recharge", appVersion, vc.AuditVersion, allow, err)
continue
}
// 是否在上架时间内
if (v.StartAt > 0 && v.EndAt > 0) && (nowUnix < v.StartAt || nowUnix > v.EndAt) {
continue
}
// 是否在上架区域内
if (v.Area == 1 || v.Area == 2) && area != v.Area { // 不在区域内
continue
}
if v.Area == 3 && !utils.IsInStringList(country, v.CountryList) {
continue
}
groupBanners = append(groupBanners, GroupBanner{
H5Url: v.Url,
BannerUrl: v.Image,
GroupId: groupMap[v.GroupCode],
})
}
resp.ResponseOk(c, groupBanners)
return myContext, nil
}
type RoomBanner struct {
H5Url string `json:"h5Url"` // h5链接
BannerUrl string `json:"bannerUrl"` // 图片地址
}
// @Tags 群组
// @Summary banner列表
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} RoomBanner
// @Router /v1/imGroup/roomBanners [get]
func RoomBannerList(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
model := domain.CreateModelContext(myContext)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
// 版本控制
_deviceType, _ := c.Get(mycontext.DEVICETYPE)
_appVersion, _ := c.Get(mycontext.APP_VERSION)
deviceType, appVersion := cast.ToString(_deviceType), cast.ToString(_appVersion)
vc := version_m.GetVersionControlByPlatform(model, deviceType)
allow, err := utils.CompareVersion(appVersion, fmt.Sprintf("<= %s", vc.AuditVersion))
model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v", appVersion, vc.AuditVersion, allow, err)
result := make([]RoomBanner, 0)
// 获取国家信息
country, area, err := user_m.GetUserCountryArea(model, userId)
if err != nil {
model.Log.Errorf("GroupBannerList 获取国家资源错误 userId:%d, err:%v", userId, err)
return myContext, err
}
rb := mgr_m.RoomBanner{Status: mysql.YES}
rows, err := rb.GetRoomBanners(model.Db, allow)
if err != nil {
return myContext, err
}
for _, i := range rows {
// 是否在banner设定区域内
if (i.Area == 1 || i.Area == 2) && area != i.Area { // 不在区域内
continue
}
if i.Area == 3 && !utils.IsInStringList(country, i.CountryList) {
continue
}
result = append(result, RoomBanner{
H5Url: i.Url,
BannerUrl: i.Image,
})
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 通知客户端banner列表更新
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200
// @Router /v1/imGroup/roomBanners [put]
func NotifyRoomBannerListChange(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
if !user_m.IsSuperUser(userId) {
return myContext, bizerr.NoPrivileges
}
if err = rpc.SendConfigChange(userId, rpc.RoomBannerChange); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 获取房间内的在线用户
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200 {object} OnlineUserResult
// @Router /v1/imGroup/online/users [get]
func GroupInUsers(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Query("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err := group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
myContext.Log.WithField("groupId", groupId)
userIds, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return myContext, err
}
myContext.Log.Infof("GroupInUsers userIds:%v", userIds)
cacheDate, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetGroupOnlineUser(groupId)).Result()
if err != nil {
//myContext.Log.Errorf("GroupInUsers GetRedis Get err:%v, groupId:%v", err, groupId)
//查找数据库
return GroupInUsersDb(c, myContext, userIds, groupId)
} else if cacheDate == "" {
//查找数据库
return GroupInUsersDb(c, myContext, userIds, groupId)
} else {
onlineUserResult := OnlineUserResult{}
if err := json.Unmarshal([]byte(cacheDate), &onlineUserResult); err != nil {
myContext.Log.Errorf("GroupInUsers Unmarshal err:%v", err)
//查找数据库
return GroupInUsersDb(c, myContext, userIds, groupId)
}
//对比数量
if len(userIds) != len(onlineUserResult.RedisUserIds) {
myContext.Log.Infof("GroupInUsers cache groupId:%v size:%v RedisUserIds size:%v", groupId, len(userIds), len(onlineUserResult.RedisUserIds))
//查找数据库
return GroupInUsersDb(c, myContext, userIds, groupId)
} else {
//对比顺序
for i, _ := range userIds {
//出现不一致
if userIds[i] != onlineUserResult.RedisUserIds[i] {
myContext.Log.Infof("GroupInUsers cache groupId:%v RedisUserIds userId no same", groupId)
return GroupInUsersDb(c, myContext, userIds, groupId)
}
}
myContext.Log.Infof("GroupInUsers cache groupId:%v hit", groupId)
resp.ResponseOk(c, onlineUserResult)
return myContext, nil
}
}
}
type OnlineUserResult struct {
Total int `json:"total"`
Users []*user_cv.CvUserBase `json:"users"`
ServiceTime int64 `json:"serviceTime"`
//利用这个来判断是否要更新缓存
RedisUserIds []uint64 `json:"redisUserIds"`
}
//显示的最大数量是15个。
func GroupInUsersDb(c *gin.Context, myContext *mycontext.MyContext, userIds []uint64, groupId string) (*mycontext.MyContext, error) {
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
if len(userIds) == 0 {
if err != nil {
return myContext, err
}
resp.ResponseOk(c, OnlineUserResult{
Total: len(userIds),
Users: nil,
})
return myContext, nil
}
//贵族
nobleLevelMap, err := noble_m.BatchGetNobleLevel(mysql.Db, userIds)
if err != nil {
return myContext, err
}
vipMap, err := user_m.BatchGetVips(userIds)
if err != nil {
return myContext, err
}
//
var maxNum int = 15
vipList := make([]uint64, 0, maxNum)
userList := make([]uint64, 0, maxNum)
//认为需求中,不会再增加贵族6,贵族7了
nobleLevel5 := make([]uint64, 0, maxNum)
nobleLevel4 := make([]uint64, 0, maxNum)
nobleLevel3 := make([]uint64, 0, maxNum)
nobleLevel2 := make([]uint64, 0, maxNum)
nobleLevel1 := make([]uint64, 0, maxNum)
//
for i, userId := range userIds {
if len(vipList)+len(userList) >= maxNum {
break
}
if level, flag := nobleLevelMap[userId]; flag {
if level == 5 {
nobleLevel5 = append(nobleLevel5, userId)
} else if level == 4 {
nobleLevel4 = append(nobleLevel4, userId)
} else if level == 3 {
nobleLevel3 = append(nobleLevel3, userId)
} else if level == 2 {
nobleLevel2 = append(nobleLevel2, userId)
} else if level == 1 {
nobleLevel1 = append(nobleLevel1, userId)
} else if level == 0 {
if vipMap[userIds[i]] != nil {
vipList = append(vipList, userIds[i])
} else {
userList = append(userList, userIds[i])
}
}
}
}
myContext.Log.Infof("GroupInUsers vip and noble ready")
//进入房间时间排序
roomUsers := []uint64{}
if err := mysql.Db.Model(&group_m.GroupUser{}).Select("user_id").Where(&group_m.GroupUser{
GroupId: groupId,
}).Where("user_id IN (?)", userList).Order("in_room_time DESC").Find(&roomUsers).Error; err != nil {
return myContext, err
}
//转换成map
roomUserMap := map[uint64]struct{}{}
for i, _ := range roomUsers {
roomUserMap[roomUsers[i]] = struct{}{}
}
//
resultList := make([]uint64, 0, maxNum)
resultList = append(resultList, nobleLevel5...)
resultList = append(resultList, nobleLevel4...)
resultList = append(resultList, nobleLevel3...)
resultList = append(resultList, nobleLevel2...)
resultList = append(resultList, nobleLevel1...)
resultList = append(resultList, vipList...)
resultList = append(resultList, roomUsers...)
//预防groupRoom中没有数据的,毕竟进入房间的时候,异常没有处理
for i, _ := range userList {
if _, flag := roomUserMap[userList[i]]; !flag {
resultList = append(resultList, userList[i])
}
}
myContext.Log.Infof("GroupInUsers resultList ready")
userBaseMap, err := user_cv.GetUserBaseMap(resultList, userId)
if err != nil {
return myContext, err
}
users := make([]*user_cv.CvUserBase, 0, maxNum)
for i, _ := range resultList {
if u, flag := userBaseMap[resultList[i]]; flag {
users = append(users, u)
}
}
onlineUserResult := OnlineUserResult{
Total: len(userIds),
Users: users,
ServiceTime: time.Now().Unix(),
RedisUserIds: userIds,
}
resp.ResponseOk(c, onlineUserResult)
if bytes, err := json.Marshal(onlineUserResult); err != nil {
myContext.Log.Errorf("GroupInUsers Marshal err:%v", err)
} else {
if _, err := redisCli.GetRedis().Set(context.Background(), redis_key.GetGroupOnlineUser(groupId), string(bytes), 5*time.Minute).Result(); err != nil {
myContext.Log.Infof("GroupInUsers cache Set groupId:%v, err:%v", groupId, err)
} else {
myContext.Log.Infof("GroupInUsers cache success groupId:%v", groupId)
}
}
return myContext, nil
}
// @Tags 群组
// @Summary 获取房间内的在线用户
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200 {object} group_m.RoomOnlineUser
// @Router /v1/imGroup/online/users/new [get]
func GroupInUserNew(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Query("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err := group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
roomOnlineUser, err := group_m.GetRoomOnlineUser(myContext, groupId)
//roomOnlineUser, err := cv.GetGroupInUser(myContext, groupId)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, roomOnlineUser)
return myContext, nil
}
// @Tags 群组
// @Summary 获取勋章
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200 {object} ResultGroupTheme
// @Router /v1/imGroup/medal/all [get]
func GroupMedalAll(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Query("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err := group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
resMedals := []res_m.ResMedal{}
if err := mysql.Db.Model(&res_m.ResMedal{}).Joins("inner join group_medal m on m.res_medal_id = res_medal.id").Where("m.im_group_id = ?", groupId).Order("m.id desc").Find(&resMedals).Error; err != nil {
return myContext, err
}
returnGroupMedals := make([]medal_cv.ReturnGroupMedal, 0, len(resMedals)+1)
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, groupId)
if err != nil {
model.Log.Infof("GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
returnGroupMedals = append(returnGroupMedals, medal_cv.ReturnGroupMedal{PicUrl: pe.PicUrl})
}
for _, r := range resMedals {
returnGroupMedals = append(returnGroupMedals, medal_cv.ReturnGroupMedal{
PicUrl: r.PicUrl,
SvgaUrl: r.SvgaUrl,
})
}
resp.ResponseOk(c, returnGroupMedals)
return myContext, nil
} // @Tags 群组
// @Tags 群组
// @Summary 查询房间勋章
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string false "群ID"
// @Success 200 {object} cv.RoomMedalInfo
// @Router /v1/imGroup/medal/room [get]
func GetRoomMedal(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
groupId := c.Query("groupId")
result := make([]group_cv.RoomMedalInfo, 0)
model := domain.CreateModelContext(myContext)
var consumeTotal uint64
if len(groupId) > 0 {
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, bizerr.GroupNotFound
}
} else {
groups, err := group_m.FindGroupByOwner(model, userId)
if err != nil {
return myContext, err
}
if len(groups) > 0 {
groupId = groups[0].ImGroupId
}
}
if len(groupId) > 0 {
consumeTotal, err = gift_cv.GetGroupConsumeTotal(model, groupId)
if err != nil {
return myContext, err
}
}
model.Log.Infof("Room %s totoal consume = %d", groupId, consumeTotal)
rec, err := res_m.GetRoomMedalConfig(model.Db)
if err != nil {
return myContext, err
}
ui, err := user_m.GetUser(model, userId)
if err != nil {
return myContext, err
}
lang := utils.DEFAULT_LANG
if len(ui.Language) > 0 {
lang = ui.Language
}
template, err := res_m.GetResMultiTextBy(model.Db, msg_e.MSG_ID_ROOM_MEADAL, lang)
if err != nil {
template = nil
}
for _, i := range rec {
previewUrl := i.InactiveUrl
if consumeTotal >= i.Threshold {
previewUrl = i.ActiveUrl
}
desc := i.Desc
if template != nil {
num := strconv.Itoa(int(i.Threshold)/1000000) + "M"
desc = fmt.Sprintf(template.Content, num)
}
result = append(result, group_cv.RoomMedalInfo{
Level: i.Level,
PreviewUrl: previewUrl,
PicUrl: i.ActiveUrl,
Desc: desc,
})
}
resp.ResponseOk(c, result)
return myContext, nil
}
......@@ -16,6 +16,7 @@ import (
"hilo-group/cv/medal_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
......@@ -1141,3 +1142,321 @@ func buildRoleMembers(model *domain.Model, groupId string, userId uint64) ([]gro
})
return roleMembers, myRole, nil
}
// @Tags 群组
// @Summary 国家A,群主是属于国家A下的群
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param countryShortName query string true "国家缩写"
// @Param pageSize query int true "分页大小 默认:10" default(10)
// @Param pageIndex query int true "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} cv.PopularGroupInfo
// @Router /v1/imGroup/country [get]
func GetGroupByCountry(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
countryShortName := c.Query("countryShortName")
if countryShortName == "" {
return myContext, myerr.NewSysError("countryShortName 为必填项")
}
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
}
model := domain.CreateModelContext(myContext)
bannedGroups, err := group_m.GetBannedGroupsMap(model)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupByCountry: page size = %d, page index = %d, banMap %v", pageSize, pageIndex, bannedGroups)
beginTime := time.Now()
groups, banCount, visitCount, err := getCandidatesByCountry(model, bannedGroups, countryShortName)
if err != nil {
return myContext, err
}
endTime := time.Now()
model.Log.Infof("GetGroupByCountry: candidates size = %d, takes %d ms banned = %d, visitCount size = %d",
len(groups), endTime.Sub(beginTime).Milliseconds(), banCount, len(visitCount))
model.Log.Infof("GetGroupByCountry cost1:%v", time.Now().Sub(beginTime))
hotGroupList := make([]*group_m.GroupInfo, 0)
// 获取麦上有人的所有群组及麦上人数
micGroupNum, err := group_m.GetMicHasInGroupNum(model)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupByCountry, micGroupNum : %v", micGroupNum)
model.Log.Infof("GetGroupByCountry cost2:%v", time.Now().Sub(beginTime))
sortedGroupIds := make([]string, 0)
diamondGroupIds := make([]string, 0)
for i, _ := range groups {
// 麦上没人也放出来
sortedGroupIds = append(sortedGroupIds, i)
// 麦上有人才计算流水
if micGroupNum[i] > 0 {
diamondGroupIds = append(diamondGroupIds, i)
}
}
now := time.Now()
bTime := now.Add(-time.Minute * 30)
g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType}
diamonds, err := g.GetRangeConsumeSummaryV2(bTime, now, diamondGroupIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupByCountry, diamonds in 30 mins: %v", diamonds)
model.Log.Infof("GetGroupByCountry cost3:%v", time.Now().Sub(beginTime))
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupByCountry, supportLevels : %v", supportLevels)
model.Log.Infof("GetGroupByCountry cost4:%v", time.Now().Sub(beginTime))
// 排序优先级2022-07-25
sort.Slice(sortedGroupIds, func(i, j int) bool {
gi := sortedGroupIds[i]
gj := sortedGroupIds[j]
// 1、按麦上人数多少排序
if micGroupNum[gi] > micGroupNum[gj] {
return true
} else if micGroupNum[gi] < micGroupNum[gj] {
return false
}
// 2、麦上人数相同,按30分钟内送礼钻石数排序
if diamonds[gi] > diamonds[gj] {
return true
} else if diamonds[gi] < diamonds[gj] {
return false
}
// 3. 根据热度排序groupInUserDuration
if visitCount[gi] > visitCount[gj] {
return true
} else if visitCount[gi] < visitCount[gj] {
return false
}
// * Final resort: 群组CODE,短号优先,然后按字母序
return len(groups[gi].Code) < len(groups[gj].Code) || len(groups[gi].Code) == len(groups[gj].Code) && groups[gi].Code < groups[gj].Code
})
model.Log.Infof("GetGroupByCountry cost5:%v", time.Now().Sub(beginTime))
// for pretty log
//logstr := ""
// * 同语言区 ^ 麦上有人 + 开放群 - 需要等级的群
for _, i := range sortedGroupIds {
hotGroupList = append(hotGroupList, groups[i])
//prefix := " "
//if micGroupNum[i] > 0 {
//prefix += "^"
//}
//logstr += prefix + i + ":" + groups[i].Code + ":" +
// strconv.Itoa(int(supportLevels[i])) + ":" + strconv.Itoa(int(micGroupNum[i])) + ":" + strconv.Itoa(int(visitCount[i]))
}
total := len(hotGroupList)
model.Log.Infof("GetGroupByCountry: size = %d, %s", total)
result := make([]group_cv.PopularGroupInfo, 0)
beginPos := pageSize * (pageIndex - 1)
endPos := pageSize * pageIndex
if beginPos < total {
if endPos > total {
endPos = total
}
groupIds := make([]string, 0)
owners := make([]uint64, 0)
for _, i := range hotGroupList[beginPos:endPos] {
groupIds = append(groupIds, i.ImGroupId)
owners = append(owners, i.Owner)
}
powerIds, powerNames, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return myContext, err
}
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return myContext, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupByCountry: final start = %d, end = %d, groupIds %v", beginPos, endPos, groupIds)
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds)
if err != nil {
return myContext, err
}
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, err
}
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
for _, i := range hotGroupList[beginPos:endPos] {
var maxStage *uint16 = nil
if s, ok := maxStageMap[i.ImGroupId]; ok {
maxStage = &s
}
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[i.ImGroupId]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
}
}
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, i.ImGroupId)
if err != nil {
model.Log.Infof("GetGroupByCountry: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
var password *string = nil
if len(i.Password) > 0 && i.Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
result = append(result, group_cv.PopularGroupInfo{
GroupInfo: group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: i.TxGroupId,
Name: i.Name,
Introduction: i.Introduction,
Notification: i.Notification,
FaceUrl: i.FaceUrl,
Code: i.Code,
CountryIcon: countryInfo[i.Country],
Password: password,
SupportLevel: supportLevels[i.ImGroupId],
GroupInUserDuration: visitCount[i.ImGroupId],
MicNumType: int(i.MicNumType),
GroupMedals: medals,
},
HasOnMic: micGroupNum[i.ImGroupId] > 0,
GroupPowerId: powerIds[i.Owner],
GroupPowerName: powerNames[i.Owner],
},
MicUsers: []user_cv.CvUserTiny{},
RoomUserCount: uint(roomCount[i.ImGroupId]),
MaxStage: maxStage,
GameTypes: games[i.TxGroupId],
})
}
}
model.Log.Infof("GetGroupByCountry cost6:%v", time.Now().Sub(beginTime))
resp.ResponsePageOk(c, result, uint(total), pageIndex)
return myContext, nil
}
// 国家群候选:没有密码且没被封禁的群, 有国家
func getCandidatesByCountry(model *domain.Model, bannedGroups map[string]uint64, country string) (map[string]*group_m.GroupInfo, int, map[string]int64, error) {
noPwdGroups, err := group_m.FindOwnerCountryGroups(model, country)
if err != nil {
return nil, 0, nil, err
}
roomVisitCount, err := room_c.GetAllRoomVisitCount()
if err != nil {
return nil, 0, nil, err
}
banCount := 0
groups := make(map[string]*group_m.GroupInfo, 0)
visitCount := make(map[string]int64)
for i, v := range noPwdGroups {
// 过滤掉被封禁的群
if bannedGroups[v.ImGroupId] != 0 {
banCount++
continue
}
// 先从二级缓存中找
if c, ok := roomVisitCount[v.ImGroupId]; ok {
if vc, err := strconv.ParseInt(c, 10, 64); err == nil && vc > 0 {
//model.Log.Debugf("getPopularCandidates, from roomVisitCount %s(%s) - %d", v.ImGroupId, v.Code, vc)
groups[v.ImGroupId] = &noPwdGroups[i]
visitCount[v.ImGroupId] = vc
}
} else {
// 如果没有,就从roomVisit中取
if vc, err := room_c.GetSetRoomVisitCount(v.ImGroupId); err == nil && vc > 0 {
model.Log.Infof("getPopularCandidates, from roomVisit %s(%s) - %d", v.ImGroupId, v.Code, vc)
groups[v.ImGroupId] = &noPwdGroups[i]
visitCount[v.ImGroupId] = vc
}
}
}
return groups, banCount, visitCount, nil
}
// @Tags 资源
// @Summary 国家资源
// @Param token header string true "token"
// @Param timestamp header string true "时间戳"
// @Param nonce header string true "随机数字"
// @Param signature header string true "sha1加密结果"
// @Param deviceType header string true "系统类型 ios android"
// @Param deviceVersion header string true "系统版本"
// @Success 200 {object} cv.CvCountry
// @Router /v1/imGroup/country/prior [get]
func GroupountryPrior(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
//沙特、科威特、伊拉克、阿尔及利亚、印度、菲律宾、土耳其
//沙特,伊拉克,科威特,土耳其。印度,巴基斯坦,印尼
resCountry, err := res_m.GetAllCountryByFilter(domain.CreateModelNil(), []string{"KSA", "Iraq", "Kuwait", "Turkey", "India", "Pakistan", "Indonesia"})
if err != nil {
return myContext, err
}
var cvContrys []group_cv.CvCountry
for i := 0; i < len(resCountry); i++ {
cvContrys = append(cvContrys, group_cv.CvCountry{
Name: &resCountry[i].Name,
ShortName: &resCountry[i].ShortName,
Icon: &resCountry[i].Icon,
Code: &resCountry[i].Code,
})
}
resp.ResponseOk(c, cvContrys)
return myContext, nil
}
package group_r
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"hilo-group/_const/enum/diamond_e"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/task_e"
"hilo-group/cv/diamond_cv"
"hilo-group/cv/group_cv"
"hilo-group/cv/mic_cv"
"hilo-group/domain/cache/mic_c"
"hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/task_m"
"hilo-group/domain/service/group_mic_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req"
"hilo-group/resp"
"strconv"
"time"
)
// @Tags 群组
// @Summary 麦位所有信息(支持高频获取,前端可以高频获取,进行校正), v2.5.0_2_211025 版本之前,只能获取5个麦位,兼容于旧版本数据
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid query string true "groupUuid"
// @Success 200 {object} group_cv.CvMic
// @Router /v1/imGroup/mic/all [get]
func GroupMicAllInfoFive(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.Query("groupUuid")
userId, extendId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
group_m.UpdateMicExpire(model, groupUuid, extendId)
//加入房间 || 更新房间内有人信息
//group_m.RoomLivingIn(model, groupUuid, userId)
//降低频率
group_m.RoomLivingExpire(model, groupUuid, userId)
mics, micUsers, err := group_m.GetAllMic(groupUuid, group_e.FiveMicNumType)
if err != nil {
return myContext, err
}
cvMics, err := group_cv.GetGroupMicAll(mics, micUsers)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, cvMics)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位所有信息(支持高频获取,前端可以高频获取,进行校正)(v2.5.0_2_211025 版本之后,根据类型返回5或者10个麦位信息,数量决定了类型)
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid query string true "groupUuid"
// @Success 200 {object} group_cv.CvMic
// @Router /v1/imGroup/mic/all/type [get]
func GroupMicAllInfoTen(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.Query("groupUuid")
userId, extendId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
group_m.UpdateMicExpire(model, groupUuid, extendId)
//加入房间 || 更新房间内有人信息
//group_m.RoomLivingIn(model, groupUuid, userId)
//降低频率
group_m.RoomLivingExpire(model, groupUuid, userId)
micNumType, err := group_m.GetMicNumType(model, groupUuid)
if err != nil {
return myContext, err
}
//兼容于旧版本
n := group_m.GetMicNum(micNumType)
if n >= 10 {
micNumType = group_e.TenMicNumType
} else {
micNumType = group_e.FiveMicNumType
}
mics := []group_m.Mic{}
micUsers := []group_m.MicUser{}
mics, micUsers, err = group_m.GetAllMic(groupUuid, micNumType)
if err != nil {
return myContext, err
}
cvMics, err := group_cv.GetGroupMicAll(mics, micUsers)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, cvMics)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位所有信息(支持高频获取,前端可以高频获取,进行校正)(v2.5.0_2_211025 版本之后,根据类型返回5或者10个麦位信息,数量决定了类型)
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid query string true "groupUuid"
// @Success 200 {object} group_cv.CvMic
// @Router /v1/imGroup/mic/all/type/new [get]
func GroupMicAllInfoType(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.Query("groupUuid")
userId, extendId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
group_m.UpdateMicExpire(model, groupUuid, extendId)
//加入房间 || 更新房间内有人信息
//group_m.RoomLivingIn(model, groupUuid, userId)
//降低频率
group_m.RoomLivingExpire(model, groupUuid, userId)
micNumType, err := group_m.GetMicNumType(model, groupUuid)
if err != nil {
return myContext, err
}
var mics []group_m.Mic
var micUsers []group_m.MicUser
mics, micUsers, err = group_m.GetAllMic(groupUuid, micNumType)
if err != nil {
return myContext, err
}
cvMics, err := group_cv.GetGroupMicAll(mics, micUsers)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, cvMics)
return myContext, nil
}
// @Tags 群组
// @Summary 修改麦位数量
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param micNumType formData int true "麦位数量类型 1:5个麦位 2:10个麦位, 当:micOn=fales, micNumType值不采纳,传的是0" //当:micOn=fales, micNumType值不采纳:这是前端要求的
// @Param micOn formData bool true "是否打开麦位"
// @Success 200
// @Router /v1/imGroup/mic/num [put]
func GroupMicNumChange(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, nil
}
groupId := c.PostForm("groupId")
if groupId == "" {
return myContext, myerr.NewSysError("参数micNumType 不能为空")
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
micNumType, err := strconv.ParseUint(c.PostForm("micNumType"), 10, 8)
if err != nil {
return myContext, myerr.NewSysError("参数groupId 不能为空")
}
micOn, err := strconv.ParseBool(c.PostForm("micOn"))
if err != nil {
return myContext, myerr.NewSysError("参数micOn 有误")
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicNumChange(groupId, userId, group_e.GroupMicNumType(micNumType), micOn); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 查询麦位数量。返回的是枚举。
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200
// @Router /v1/imGroup/mic/num [get]
func GroupMicNum(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
txGroupId := c.Query("groupId")
groupInfo, err := group_m.GetInfoByTxGroupId(domain.CreateModelContext(myContext), txGroupId)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, groupInfo.MicNumType)
return myContext, nil
}
// @Tags 群组
// @Summary 麦上表情信令
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param micEmojiId formData int true "麦上表情ID"
// @Success 200
// @Router /v1/imGroup/mic/emoji/msg [post]
func GroupSendMicSystemMsg(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
_, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, nil
}
txGroupId := c.PostForm("groupId")
if txGroupId == "" {
return myContext, myerr.NewSysError("参数groupId 不能为空")
}
micEmojiId, err := strconv.ParseUint(c.PostForm("micEmojiId"), 10, 64)
if err != nil {
return myContext, myerr.WrapErr(err)
}
//
resMicEmoji := res_m.ResMicEmoji{}
if err := mysql.Db.Model(&res_m.ResMicEmoji{}).First(&resMicEmoji, micEmojiId).Error; err != nil {
return myContext, myerr.WrapErr(err)
}
if resMicEmoji.Status == mysql.NOUSER {
return myContext, myerr.NewSysError("表情已下架")
}
buf, err := json.Marshal(mic_cv.CvMicEmoji{
Id: resMicEmoji.ID,
Name: resMicEmoji.Name,
IconUrl: resMicEmoji.IconUrl,
SvagUrl: resMicEmoji.SvagUrl,
})
if err != nil {
return myContext, myerr.WrapErr(err)
}
//
model := domain.CreateModelContext(myContext)
if err := group_m.MicRPush(model, txGroupId, group_m.GroupSystemMsg{
MsgId: group_e.GroupMicEmoji,
Source: externalId,
Content: string(buf),
}); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
type ReturnFlag struct {
Flag bool `json:"flag"`
//1:邀请上麦 2:未完成任务上麦任务
Type uint `json:"type"`
//钻石数量(2:未完成任务上麦任务才有值)
DiamondNum uint32 `json:"diamondNum"`
}
// @Tags 群组
// @Summary 邀请上麦校验弹窗
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Success 200 {object} ReturnFlag
// @Router /v1/imGroup/mic/in/invite/dialog [post]
func GroupMicInInviteDialog(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
_, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, nil
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return nil, err
}
groupId = groupInfo.ImGroupId
mics, micUsers, err := group_m.GetAllMic(groupId, groupInfo.MicNumType)
if err != nil {
return myContext, err
}
cvMics, err := group_cv.GetGroupMicAll(mics, micUsers)
//用户没有上麦
micInFlag := false
//群组麦上有人
micHasUserFlag := false
//有空余麦位
micSpareFlag := false
for _, r := range cvMics {
//用户在麦上
if r.ExternalId != nil && *(r.ExternalId) == externalId {
micInFlag = true
}
//麦上有人
if r.ExternalId != nil && *(r.ExternalId) != externalId {
micHasUserFlag = true
}
if r.ExternalId == nil && r.Lock == false {
micSpareFlag = true
}
}
if micInFlag == false && micHasUserFlag == true && micSpareFlag == true {
resp.ResponseOk(c, ReturnFlag{Flag: true})
return myContext, nil
} else {
resp.ResponseOk(c, ReturnFlag{
Flag: false,
Type: 1,
DiamondNum: 0,
})
return myContext, nil
}
}
// @Tags 群组
// @Summary 邀请上麦钻石校验弹窗
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Success 200 {object} ReturnFlag
// @Router /v1/imGroup/mic/task/invite/dialog [post]
func GroupMicTaskInviteDialog(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, nil
}
groupId := c.PostForm("groupId")
if groupId == "" {
return myContext, myerr.NewSysError("参数groupId 不能为空")
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
groupId = groupInfo.ImGroupId
mics, micUsers, err := group_m.GetAllMic(groupId, groupInfo.MicNumType)
if err != nil {
return myContext, err
}
cvMics, err := group_cv.GetGroupMicAll(mics, micUsers)
//用户没有上麦
micInFlag := false
//群组麦上有人
micHasUserFlag := false
//有空余麦位
micSpareFlag := false
for _, r := range cvMics {
//用户在麦上
if r.ExternalId != nil && *(r.ExternalId) == externalId {
micInFlag = true
}
//麦上有人
if r.ExternalId != nil && *(r.ExternalId) != externalId {
micHasUserFlag = true
}
if r.ExternalId == nil && r.Lock == false {
micSpareFlag = true
}
}
if micInFlag == false && micHasUserFlag == true && micSpareFlag == true {
// 今天展示过了
if show, _ := mic_c.IsMicDayInviteDialogShowToday(model, userId); show {
resp.ResponseOk(c, ReturnFlag{
Flag: false,
})
return myContext, nil
}
//产品说:同是否能领取了每日钻石关联起来
beginTime := utils.GetZeroTime(time.Now())
endTime := beginTime.AddDate(0, 0, 1)
var n int64
if err := mysql.Db.Model(&diamond_m.DiamondAccountDetail{}).Where(&diamond_m.DiamondAccountDetail{
UserId: userId,
AddReduce: mysql.ADD,
}).Where("Created_Time <= ? and Created_Time >= ?", endTime, beginTime).Where("(Operate_Type = ? or Operate_Type = ?)", diamond_e.DailyInAppVip, diamond_e.DailyInAppCommon).Count(&n).Error; err != nil {
if err != nil {
return myContext, nil
}
}
if n > 0 {
//判断是否完成上麦任务
taskConfig := task_m.TaskConfig{}
if err := mysql.Db.Model(&task_m.TaskConfig{}).Where(&task_m.TaskConfig{
Type: task_e.MicIn,
}).First(&taskConfig).Error; err != nil {
if err == gorm.ErrRecordNotFound {
} else {
return myContext, myerr.WrapErr(err)
}
}
//任务还存在
if taskConfig.ID != 0 {
var n int64
if err := mysql.Db.Model(&task_m.TaskUser{}).Where(&task_m.TaskUser{
TaskConfigId: taskConfig.ID,
UserId: userId,
DayStr: time.Now().Format(utils.COMPACT_DATE_FORMAT),
HasFinish: mysql.YES,
}).Count(&n).Error; err != nil {
return myContext, myerr.WrapErr(err)
}
//存在还没完成
if n == 0 {
resp.ResponseOk(c, ReturnFlag{
Flag: true,
Type: 2,
DiamondNum: taskConfig.Diamond,
})
return myContext, nil
}
}
}
resp.ResponseOk(c, ReturnFlag{
Flag: true,
Type: 1,
})
return myContext, nil
} else {
resp.ResponseOk(c, ReturnFlag{
Flag: false,
Type: 1,
DiamondNum: 0,
})
return myContext, nil
}
}
// @Tags 群组
// @Summary 上麦
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string false "麦序, 空字符串,代表有麦位就上"
// @Success 200
// @Router /v1/imGroup/mic/in [post]
func GroupMicIn(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
nonce := c.GetHeader("nonce")
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
groupUuid = groupInfo.ImGroupId
// 游客,且设置了游客不能上麦,则失败
// nonce = hilo,服务端内部调用,机器人
if groupInfo.TouristMic != 1 && nonce != "hilo" {
role, err := GetGroupRoleById(model, groupInfo.ImGroupId, userId)
if err != nil {
return myContext, err
}
if role == group_e.GROUP_VISITOR {
// 旧版本(2.32.0以下),提示升级
_, major, minor, _, err := req.GetAppVersion(c)
if err != nil {
return myContext, err
}
if major <= 2 && minor < 32 {
return myContext, bizerr.UpgradeRequired
}
return myContext, bizerr.GroupMicBanTourist
}
}
iStr := c.PostForm("i")
micIndex := -1
// 用户已经在麦上,必须先下麦!
micUser, err := group_m.GetMicUserByExternalId(model, externalId)
if err != nil {
return myContext, err
}
if micUser != nil {
if iStr == "" {
// 非切麦操作
return myContext, bizerr.GroupMicUserHasIn
}
// 切换麦位,先下麦
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicLeave(groupUuid, micUser.I, userId, externalId); err != nil {
return myContext, err
}
}
if iStr == "" {
//判断群组设置上的麦 是否被关闭
if groupInfo.MicOn == false {
return myContext, bizerr.GroupInfoMicClosed
}
//micNum := 5
//if groupInfo.MicNumType == group_enum.TenMicNumType {
// micNum = 10
//}
micNum := group_m.GetMicNum(groupInfo.MicNumType)
for i := 1; i <= micNum; i++ {
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicIn(groupUuid, i, userId, externalId); err != nil {
if i == micNum {
//最后一次了,依旧错误,则
return myContext, bizerr.GroupMicInByInviteFail
}
} else {
//成功则跳出
micIndex = i
break
}
}
} else {
i, err := strconv.Atoi(iStr)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicIn(groupUuid, i, userId, externalId); err != nil {
return myContext, err
}
micIndex = i
}
data := map[string]interface{}{
"micIndex": micIndex,
}
if nonce == "hilo" {
resp.ResponseOk(c, data)
} else {
resp.ResponseOk(c, nil)
}
return myContext, nil
}
func GetGroupRoleById(model *domain.Model, imGroupId string, userId uint64) (role group_e.GroupRoleType, err error) {
role = group_e.GROUP_VISITOR
roles, _, err := group_m.GetRolesInGroup(model, imGroupId)
if err != nil {
return
}
for u, r := range roles {
if u == userId {
role = r
return
}
}
isGroupMember, err := group_m.IsGroupMember(model.Db, imGroupId, userId)
if err != nil {
return
}
if isGroupMember {
role = group_e.GROUP_MEMBER
}
return
}
// @Tags 群组
// @Summary 邀请上麦
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param beInvitedExternalId formData string false "被邀请人的ExternalId"
// @Success 200
// @Router /v1/imGroup/mic/invite [post]
func GroupMicInvite(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
beInvitedExternalId := c.PostForm("beInvitedExternalId")
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicInvite(groupUuid, userId, beInvitedExternalId); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 自己离开麦位, 管理人让他下麦
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/leave [post]
func GroupMicLeave(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
_, lang, err := req.GetUserIdLang(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
}
micUser, err := group_m.GetMicUser(model, groupId, i)
if err != nil {
return myContext, err
}
if micUser != nil && micUser.UserId != userId { // 抱下麦
// 检查权限
if err = CheckOptToSvip6(model, userId, micUser.UserId, lang, 11); err != nil {
return myContext, err
}
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicLeave(groupId, i, userId, externalId); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位加锁
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/lock [post]
func GroupMicLock(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicLock(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位解锁
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/unlock [post]
func GroupMicUnLock(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicUnLock(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 开麦(可以说话)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/speech/open [post]
func GroupMicSpeechOpen(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicSpeechOpen(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 关麦(不可以说话),管理人禁言这个麦位
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/speech/close [post]
func GroupMicSpeechClose(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicSpeechClose(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位解除静音(打开座位)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/unmute [post]
func GroupMicUnmute(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicUnMute(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 麦位静音(关闭座位)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupUuid formData string true "groupUuid"
// @Param i formData string true "麦序"
// @Success 200
// @Router /v1/imGroup/mic/mute [post]
func GroupMicMute(c *gin.Context) (*mycontext.MyContext, error) {
// todo
myContext := mycontext.CreateMyContext(c.Keys)
groupUuid := c.PostForm("groupUuid")
i, err := strconv.Atoi(c.PostForm("i"))
if err != nil {
return myContext, err
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupUuid, err = group_m.ToImGroupId(model, groupUuid)
if err != nil {
return myContext, err
}
if err := group_mic_s.NewGroupPowerService(myContext).GroupMicMute(userId, externalId, groupUuid, i); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 麦上用户群发成员广播
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param content formData string true "内容"
// @Success 200 {object} cv.CvDiamond
// @Router /v1/imGroup/mic/mass [post]
func GroupMicMass(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
content := c.PostForm("content")
if err := group_mic_s.NewGroupPowerService(myContext).GroupIMMassByInMic(groupId, userId, externalId, content); err != nil {
return myContext, err
}
diamond, err := diamond_cv.GetDiamond(userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
resp.ResponseOk(c, diamond)
return myContext, nil
}
// @Tags 群组
// @Summary 用户群发成员广播
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param content formData string true "内容"
// @Success 200 {object} cv.CvDiamond
// @Router /v1/imGroup/mgr/mass [post]
func GroupMgrMass(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
content := c.PostForm("content")
if err := group_mic_s.NewGroupPowerService(myContext).GroupIMMassByMgr(groupId, userId, externalId, content); err != nil {
return myContext, err
}
diamond, err := diamond_cv.GetDiamond(userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
resp.ResponseOk(c, diamond)
return myContext, nil
}
......@@ -25,9 +25,14 @@ import (
"hilo-group/cv/gift_cv"
"hilo-group/cv/group_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/game_c"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/cache/tim_c"
"hilo-group/domain/cache/user_c"
"hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
......@@ -1101,7 +1106,7 @@ func AddPermanentMember(c *gin.Context) (*mycontext.MyContext, error) {
// fixme: 这些缓存还需要吗?
group_c.ClearGroupMemberCount(groupId)
group_c.AddGroupMember(model, groupId, externalId)
tim_c.AddGroupMember(model, groupId, externalId)
if isInvite == 1 && !needCost { // 已经接受了进群邀请
group_m.AcceptGroupInviteJoin(model, userId, groupId)
......@@ -1703,3 +1708,218 @@ func downgradeRoom(myContext *mycontext.MyContext, gi *group_m.GroupInfo) error
}
return nil
}
// @Tags 群组
// @Summary 进入房间
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param password formData string false "房间密码"
// @Param enterType formData int false "进房类型:1.ludo游戏快速匹配进房 2:uno"
// @Param gameCode formData string false "gameCode"
// @Success 200 {object} group_cv.GroupChannelId
// @Router /v1/imGroup/in [put]
func GroupIn(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
password := c.PostForm("password")
enterType := c.PostForm("enterType")
gameCode := c.PostForm("gameCode")
model := domain.CreateModelContext(myContext)
gi, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if gi == nil {
return myContext, bizerr.GroupNotFound
}
groupId = gi.ImGroupId
ip := req.GetRequestIP(c)
imei, err := req.GetAppImei(c)
if err != nil {
imei, err = user_m.GetUserImeiStr(model, userId)
if err != nil {
return myContext, err
}
}
model.Log.Infof("GroupIn ip userId:%v,imGroupId:%v,ip:%v,imei:%v", userId, groupId, ip, imei)
if channelId, token, err := group_s.NewGroupService(myContext).GroupIn(userId, externalId, groupId, password, imei, ip); err != nil {
return myContext, err
} else {
// 加入房间缓存
if err = room_c.ProcessRoomVisit(groupId, userId); err != nil {
myContext.Log.Infof("GroupIn, ProcessRoomVisit err: %s", err.Error())
}
// 更新用户进入房间缓存记录
if err = room_c.ProcessUserRoomVisit(userId, groupId); err != nil {
myContext.Log.Infof("GroupIn, ProcessUserRoomVisit err: %s", err.Error())
}
resp.ResponseOk(c, group_cv.GroupChannelId{
ChannelId: channelId,
Token: token,
AgoraId: uint32(userId),
MicNumType: gi.MicNumType,
})
// v2.26及以后,客户端自己加TIM群,不再由服务器代加
_, major, minor, _, err := req.GetAppVersion(c)
if err != nil || major < 2 || major == 2 && minor < 26 {
go func() {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("GroupIn - JoinGroup, SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
err := group_s.NewGroupService(myContext).JoinGroup(userId, externalId, gi.TxGroupId)
mylogrus.MyLog.Infof("myService.JoinGroup %s, user %d, err:%v", groupId, userId, err)
}()
}
// 判断是否需要执行游戏逻辑
if enterType != "" && gameCode != "" {
traceId := c.Writer.Header().Get(mycontext.TRACEID)
token := c.Writer.Header().Get(mycontext.TOKEN)
err := game_c.SetAutoMathEnterRoom(userId, gi.ImGroupId, traceId, token, enterType, gameCode)
if err != nil {
model.Log.Errorf("GroupIn cache.SetAutoMathEnterRoom userId:%v, imGroupId:%v, err:%v", userId, gi.ImGroupId, err)
}
//go proxy.GameAfterEnterRoom(model, userId, externalId, traceId, token, enterType, gameCode, gi)
}
//// 临时
//go func() {
// time.Sleep(time.Second * 2)
// //发送全麦信息
// myContext.Log.Infof("imCallBack CallbackAfterNewMemberJoin MicAllRPush begin MemberAccount:%v, gi:%v", externalId, gi)
// if err := group_m.MicAllRPush(domain.CreateModelContext(myContext), groupId, externalId); err != nil {
// myContext.Log.Errorf("imCallBack CallbackAfterNewMemberJoin MicAllRPush err MemberAccount:%v, gi:%v,err:%v", externalId, gi, err)
// } else {
// myContext.Log.Infof("imCallBack CallbackAfterNewMemberJoin MicAllRPush success MemberAccount:%v, gi:%v,err:%v", externalId, gi, err)
// }
// //加入在线列表
// user, err := user_m.GetUserByExtId(domain.CreateModelContext(myContext), externalId)
// if err != nil {
// myContext.Log.Errorf("imCallBack CallbackAfterNewMemberJoin RoomLivingIn GetUserByExtId err:%+v, MemberAccount:%v", err, externalId)
// }
// //添加用户在线列表
// err = group_m.RoomLivingIn(domain.CreateModelContext(myContext), groupId, user.ID, user.ExternalId, false)
// if err != nil {
// myContext.Log.Errorf("imCallBack CallbackAfterNewMemberJoin err:%+v, userId:%v", err, user.ID)
// } else {
// myContext.Log.Infof("imCallBack CallbackAfterNewMemberJoin RoomLivingIn success MemberAccount:%v, gi:%v", externalId, gi)
// }
//}()
return myContext, nil
}
}
// @Tags 群组
// @Summary 离开房间
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/leave [post]
func GroupLeave(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, exteranlId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
if err := group_s.NewGroupService(myContext).GroupLeave(userId, exteranlId, groupId); err != nil {
myContext.Log.Errorf("GroupLeave GroupLeave err:%v", err)
return myContext, err
} else {
/* roomOnlineUser, err := cv.GetGroupInUser(domain.CreateModelContext(myContext), groupId)
if err != nil {
myContext.Log.Errorf("cron socketStatus cv.GetGroupInUser err:%v", err)
}
buf, err := json.Marshal(roomOnlineUser)
if err != nil {
myContext.Log.Errorf("cron socketStatus json.Marshal err:%v", err)
}
service.SendSignalMsg(groupId, group_m.GroupSystemMsg{
MsgId: group_enum.GroupOnlineUser,
Content: string(buf),
} , true)*/
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 踢人
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Param externalId formData string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/kick [post]
func GroupKick(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, nick, avatar, _, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
_, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
txGroupId := groupId
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
beKickExternalId := c.PostForm("externalId")
beKickUser, err := user_c.GetUserByExternalId(domain.CreateModelContext(myContext), beKickExternalId)
if err != nil {
return myContext, err
}
isGaming, err := game_m.IsGaming(model, beKickUser.ID, txGroupId)
if err != nil {
return myContext, err
}
if isGaming {
return myContext, bizerr.GamingCannotKick
}
if err = CheckOptToSvip6(model, userId, beKickUser.ID, lang, 10); err != nil {
return myContext, err
}
//beKickUserId, err := toUserId(beKickExternalId)
if err := group_s.NewGroupService(myContext).GroupKick(groupId, userId, externalId, nick, avatar, beKickUser.ID, beKickUser.ExternalId, beKickUser.Nick, beKickUser.Avatar); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
......@@ -4,16 +4,22 @@ import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/aws"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"hilo-group/_const/enum/diamond_e"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/mgr_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/cv/diamond_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/mgr_m"
......@@ -27,6 +33,7 @@ import (
"hilo-group/req"
"hilo-group/resp"
"strconv"
"time"
)
// @Tags 群组
......@@ -921,3 +928,214 @@ func ResetGroupInfo(c *gin.Context) (*mycontext.MyContext, error) {
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 清理公屏
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/mgr/clearScreen [post]
func GroupMgrClearScreen(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
if err := group_s.NewGroupService(myContext).GroupClearScreenByMgr(groupId, userId); err != nil {
return myContext, err
}
resp.ResponseOk(c, "")
return myContext, nil
}
type ReturnGroupThemeConfig struct {
Days int `json:"days"`
NumLimit int `json:"numLimit"`
DiamondNum int `json:"diamondNum"`
}
// @Tags 群组
// @Summary 查询自定义主题
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} ReturnGroupThemeConfig
// @Router /v1/imGroup/theme/custom/config [get]
func GroupThemeConfig(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
diamondOperateSet := diamond_m.DiamondOperateSet{}
if err := mysql.Db.Model(&diamond_m.DiamondOperateSet{}).Where(&diamond_m.DiamondOperateSet{
Type: diamond_e.GroupCustomTheme,
}).First(&diamondOperateSet).Error; err != nil {
return myContext, err
}
resp.ResponseOk(c, ReturnGroupThemeConfig{
Days: config.GetGroupCustomThemeConfig().DAY,
NumLimit: config.GetGroupCustomThemeConfig().PIC_LIMIT,
DiamondNum: diamondOperateSet.DiamondNum,
})
return myContext, nil
}
type ReturnGroupThemeAdd struct {
DiamondNum uint32 `json:"diamondNum"`
ThemeId uint64 `json:"themeId"`
ThemeUrl string `json:"themeUrl"`
}
// @Tags 群组
// @Summary 上传自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param picUrl formData string true "主题URL"
// @Param groupId formData string true "群ID"
// @Success 200 {object} ReturnGroupThemeAdd
// @Router /v1/imGroup/theme/custom [post]
func GroupThemeAdd(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
picUrl := c.PostForm("picUrl")
if picUrl == "" {
return myContext, myerr.NewSysError("参数 picUrl 不能为空")
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
switch config.GetConfigApp().MODERATE {
case "AWS":
passed, err := aws.ModerateLabels(model.Log, userId, picUrl)
if err == nil {
if !passed {
return myContext, bizerr.ImagePolicyViolation
}
} else {
model.Log.Warnf("ModerateLabels err:%v", err)
}
case "TENCENT":
label, err := tencentyun.ModerateImage(model, userId, "", utils.StripAwsPrefix(picUrl), picUrl)
if err == nil && label != "Pass" {
return myContext, bizerr.ImagePolicyViolation
}
}
themeId, themeUrl, err := group_s.NewGroupService(myContext).AddGroupCustomTheme(userId, groupId, picUrl)
if err != nil {
return myContext, err
}
diamond, err := diamond_cv.GetDiamond(userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
resp.ResponseOk(c, ReturnGroupThemeAdd{
DiamondNum: *diamond.DiamondNum,
ThemeId: themeId,
ThemeUrl: themeUrl,
})
return myContext, nil
}
// @Tags 群组
// @Summary 使用自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupCustomThemeId formData int true "自定义主题ID"
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/theme/custom/using [put]
func GroupThemeUsing(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.PostForm("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
id, err := strconv.ParseUint(c.PostForm("groupCustomThemeId"), 10, 64)
if err != nil {
return myContext, err
}
if err := group_s.NewGroupService(myContext).GroupCustomThemeUsing(userId, externalId, groupId, id); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
type ResultGroupTheme struct {
Id uint64 `json:"id"`
PicUrl string `json:"picUrl"`
RemainSecond int64 `json:"remainSecond"`
}
// @Tags 群组
// @Summary 查询有效的全部自定义主题
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string true "群ID"
// @Success 200 {object} ResultGroupTheme
// @Router /v1/imGroup/theme/custom/all [get]
func GroupThemeValidAll(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Query("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
groupId, err := group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
var groupCustomThemes []group_m.GroupCustomTheme
if err := mysql.Db.Where(&group_m.GroupCustomTheme{ImGroupId: groupId}).Where("expire_time > ?", time.Now()).Order("expire_time asc").Find(&groupCustomThemes).Error; err != nil {
return myContext, err
}
//
resultGroupThemes := make([]ResultGroupTheme, 0, len(groupCustomThemes))
now := time.Now().Unix()
for _, r := range groupCustomThemes {
resultGroupThemes = append(resultGroupThemes, ResultGroupTheme{
Id: r.ID,
PicUrl: r.PicUrl,
RemainSecond: r.ExpireTime.Unix() - now,
})
}
resp.ResponseOk(c, resultGroupThemes)
return myContext, nil
}
......@@ -73,47 +73,47 @@ func InitRouter() *gin.Engine {
imGroup.PUT("/upgrade", wrapper(group_r.UpgradeGroup))
imGroup.PUT("/downgrade", wrapper(group_r.DowngradeGroup))
//
//imGroup.GET("/mic/all", wrapper(GroupMicAllInfoFive))
//imGroup.GET("/mic/all/type", wrapper(GroupMicAllInfoTen))
//imGroup.GET("/mic/all/type/new", wrapper(GroupMicAllInfoType))
//imGroup.PUT("/mic/num", wrapper(GroupMicNumChange))
//imGroup.GET("/mic/num", wrapper(GroupMicNum))
//imGroup.POST("/mic/emoji/msg", wrapper(GroupSendMicSystemMsg))
//imGroup.POST("/mic/in/invite/dialog", wrapper(GroupMicInInviteDialog))
//imGroup.POST("/mic/task/invite/dialog", wrapper(GroupMicTaskInviteDialog))
//imGroup.POST("/mic/in", LogRequestTime, wrapper(GroupMicIn))
//imGroup.POST("/mic/invite", LogRequestTime, wrapper(GroupMicInvite))
//imGroup.POST("/mic/leave", LogRequestTime, wrapper(GroupMicLeave))
//imGroup.POST("/mic/lock", wrapper(GroupMicLock))
//imGroup.POST("/mic/unlock", wrapper(GroupMicUnLock))
//imGroup.POST("/mic/speech/open", wrapper(GroupMicSpeechOpen))
//imGroup.POST("/mic/speech/close", wrapper(GroupMicSpeechClose))
//imGroup.POST("/mic/mute", wrapper(GroupMicMute))
//imGroup.POST("/mic/unmute", wrapper(GroupMicUnmute))
//imGroup.PUT("/in", LogRequestTime, wrapper(GroupIn))
//imGroup.POST("/leave", wrapper(GroupLeave))
//imGroup.POST("/kick", wrapper(GroupKick))
//imGroup.PUT("/user/msg/status", wrapper(GroupUserMsg))
//imGroup.POST("/report", wrapper(GroupReport))
//imGroup.GET("/banner/list", wrapper(GroupBannerList))
//imGroup.GET("/roomBanners", wrapper(RoomBannerList))
//imGroup.PUT("/roomBanners", wrapper(NotifyRoomBannerListChange))
//imGroup.POST("/mic/gift", wrapper(GroupMicGift))
//imGroup.POST("/mic/mass", wrapper(GroupMicMass))
//imGroup.POST("/mgr/mass", wrapper(GroupMgrMass))
//imGroup.POST("/mgr/clearScreen", wrapper(GroupMgrClearScreen))
//imGroup.GET("/online/users", wrapper(GroupInUsers))
//imGroup.GET("/online/users/new", wrapper(GroupInUserNew))
//imGroup.GET("/country", wrapper(GetGroupByCountry))
//imGroup.GET("/country/prior", wrapper(GroupountryPrior))
imGroup.GET("/mic/all", wrapper(group_r.GroupMicAllInfoFive))
imGroup.GET("/mic/all/type", wrapper(group_r.GroupMicAllInfoTen))
imGroup.GET("/mic/all/type/new", wrapper(group_r.GroupMicAllInfoType))
imGroup.PUT("/mic/num", wrapper(group_r.GroupMicNumChange))
imGroup.GET("/mic/num", wrapper(group_r.GroupMicNum))
imGroup.POST("/mic/emoji/msg", wrapper(group_r.GroupSendMicSystemMsg))
imGroup.POST("/mic/in/invite/dialog", wrapper(group_r.GroupMicInInviteDialog))
imGroup.POST("/mic/task/invite/dialog", wrapper(group_r.GroupMicTaskInviteDialog))
imGroup.POST("/mic/in", wrapper(group_r.GroupMicIn))
imGroup.POST("/mic/invite", wrapper(group_r.GroupMicInvite))
imGroup.POST("/mic/leave", wrapper(group_r.GroupMicLeave))
imGroup.POST("/mic/lock", wrapper(group_r.GroupMicLock))
imGroup.POST("/mic/unlock", wrapper(group_r.GroupMicUnLock))
imGroup.POST("/mic/speech/open", wrapper(group_r.GroupMicSpeechOpen))
imGroup.POST("/mic/speech/close", wrapper(group_r.GroupMicSpeechClose))
imGroup.POST("/mic/mute", wrapper(group_r.GroupMicMute))
imGroup.POST("/mic/unmute", wrapper(group_r.GroupMicUnmute))
imGroup.PUT("/in", wrapper(group_r.GroupIn))
imGroup.POST("/leave", wrapper(group_r.GroupLeave))
imGroup.POST("/kick", wrapper(group_r.GroupKick))
imGroup.PUT("/user/msg/status", wrapper(group_r.GroupUserMsg))
imGroup.POST("/report", wrapper(group_r.GroupReport))
imGroup.GET("/banner/list", wrapper(group_r.GroupBannerList))
imGroup.GET("/roomBanners", wrapper(group_r.RoomBannerList))
imGroup.PUT("/roomBanners", wrapper(group_r.NotifyRoomBannerListChange))
//imGroup.POST("/mic/gift", wrapper(GroupMicGift)) // todo 先留在biz,内容有点多
imGroup.POST("/mic/mass", wrapper(group_r.GroupMicMass))
imGroup.POST("/mgr/mass", wrapper(group_r.GroupMgrMass))
imGroup.POST("/mgr/clearScreen", wrapper(group_r.GroupMgrClearScreen))
imGroup.GET("/online/users", wrapper(group_r.GroupInUsers))
imGroup.GET("/online/users/new", wrapper(group_r.GroupInUserNew))
imGroup.GET("/country", wrapper(group_r.GetGroupByCountry))
imGroup.GET("/country/prior", wrapper(group_r.GroupountryPrior))
//
//imGroup.POST("/theme/custom", wrapper(GroupThemeAdd))
//imGroup.GET("/theme/custom/config", wrapper(GroupThemeConfig))
//imGroup.PUT("/theme/custom/using", wrapper(GroupThemeUsing))
//imGroup.GET("/theme/custom/all", wrapper(GroupThemeValidAll))
imGroup.POST("/theme/custom", wrapper(group_r.GroupThemeAdd))
imGroup.GET("/theme/custom/config", wrapper(group_r.GroupThemeConfig))
imGroup.PUT("/theme/custom/using", wrapper(group_r.GroupThemeUsing))
imGroup.GET("/theme/custom/all", wrapper(group_r.GroupThemeValidAll))
//
//imGroup.GET("/medal/all", wrapper(GroupMedalAll))
//imGroup.GET("/medal/room", wrapper(GetRoomMedal))
imGroup.GET("/medal/all", wrapper(group_r.GroupMedalAll))
imGroup.GET("/medal/room", wrapper(group_r.GetRoomMedal))
}
groupPower := v1.Group("/groupPower")
......
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