复制项目
This commit is contained in:
46
internal/rpc/group/cache.go
Normal file
46
internal/rpc/group/cache.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/convert"
|
||||
pbgroup "git.imall.cloud/openim/protocol/group"
|
||||
)
|
||||
|
||||
// GetGroupInfoCache get group info from cache.
|
||||
func (g *groupServer) GetGroupInfoCache(ctx context.Context, req *pbgroup.GetGroupInfoCacheReq) (*pbgroup.GetGroupInfoCacheResp, error) {
|
||||
group, err := g.db.TakeGroup(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pbgroup.GetGroupInfoCacheResp{
|
||||
GroupInfo: convert.Db2PbGroupInfo(group, "", 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (*pbgroup.GetGroupMemberCacheResp, error) {
|
||||
if err := g.checkAdminOrInGroup(ctx, req.GroupID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
members, err := g.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pbgroup.GetGroupMemberCacheResp{
|
||||
Member: convert.Db2PbGroupMember(members),
|
||||
}, nil
|
||||
}
|
||||
476
internal/rpc/group/callback.go
Normal file
476
internal/rpc/group/callback.go
Normal file
@@ -0,0 +1,476 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/apistruct"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/callbackstruct"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/config"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/webhook"
|
||||
"git.imall.cloud/openim/protocol/constant"
|
||||
"git.imall.cloud/openim/protocol/group"
|
||||
"git.imall.cloud/openim/protocol/wrapperspb"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
// CallbackBeforeCreateGroup callback before create group.
|
||||
func (g *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *config.BeforeConfig, req *group.CreateGroupReq) error {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
GroupInfo: req.GroupInfo,
|
||||
}
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: req.OwnerUserID,
|
||||
RoleLevel: constant.GroupOwner,
|
||||
})
|
||||
for _, userID := range req.AdminUserIDs {
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupAdmin,
|
||||
})
|
||||
}
|
||||
for _, userID := range req.MemberUserIDs {
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupOrdinaryUsers,
|
||||
})
|
||||
}
|
||||
resp := &callbackstruct.CallbackBeforeCreateGroupResp{}
|
||||
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
datautil.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID)
|
||||
datautil.NotNilReplace(&req.GroupInfo.GroupName, resp.GroupName)
|
||||
datautil.NotNilReplace(&req.GroupInfo.Notification, resp.Notification)
|
||||
datautil.NotNilReplace(&req.GroupInfo.Introduction, resp.Introduction)
|
||||
datautil.NotNilReplace(&req.GroupInfo.FaceURL, resp.FaceURL)
|
||||
datautil.NotNilReplace(&req.GroupInfo.OwnerUserID, resp.OwnerUserID)
|
||||
datautil.NotNilReplace(&req.GroupInfo.Ex, resp.Ex)
|
||||
datautil.NotNilReplace(&req.GroupInfo.Status, resp.Status)
|
||||
datautil.NotNilReplace(&req.GroupInfo.CreatorUserID, resp.CreatorUserID)
|
||||
datautil.NotNilReplace(&req.GroupInfo.GroupType, resp.GroupType)
|
||||
datautil.NotNilReplace(&req.GroupInfo.NeedVerification, resp.NeedVerification)
|
||||
datautil.NotNilReplace(&req.GroupInfo.LookMemberInfo, resp.LookMemberInfo)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config.AfterConfig, req *group.CreateGroupReq) {
|
||||
cbReq := &callbackstruct.CallbackAfterCreateGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterCreateGroupCommand,
|
||||
GroupInfo: req.GroupInfo,
|
||||
}
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: req.OwnerUserID,
|
||||
RoleLevel: constant.GroupOwner,
|
||||
})
|
||||
for _, userID := range req.AdminUserIDs {
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupAdmin,
|
||||
})
|
||||
}
|
||||
for _, userID := range req.MemberUserIDs {
|
||||
cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupOrdinaryUsers,
|
||||
})
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterCreateGroupResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeMembersJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMembers []*model.GroupMember, groupID string, groupEx string) error {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
groupMembersMap := datautil.SliceToMap(groupMembers, func(e *model.GroupMember) string {
|
||||
return e.UserID
|
||||
})
|
||||
var groupMembersCallback []*callbackstruct.CallbackGroupMember
|
||||
|
||||
for _, member := range groupMembers {
|
||||
groupMembersCallback = append(groupMembersCallback, &callbackstruct.CallbackGroupMember{
|
||||
UserID: member.UserID,
|
||||
Ex: member.Ex,
|
||||
})
|
||||
}
|
||||
|
||||
cbReq := &callbackstruct.CallbackBeforeMembersJoinGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeMembersJoinGroupCommand,
|
||||
GroupID: groupID,
|
||||
MembersList: groupMembersCallback,
|
||||
GroupEx: groupEx,
|
||||
}
|
||||
resp := &callbackstruct.CallbackBeforeMembersJoinGroupResp{}
|
||||
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 记录webhook响应,用于排查自动禁言问题
|
||||
if len(resp.MemberCallbackList) > 0 {
|
||||
log.ZInfo(ctx, "webhookBeforeMembersJoinGroup: webhook response received",
|
||||
"groupID", groupID,
|
||||
"memberCallbackListCount", len(resp.MemberCallbackList),
|
||||
"memberCallbackList", resp.MemberCallbackList)
|
||||
}
|
||||
|
||||
for _, memberCallbackResp := range resp.MemberCallbackList {
|
||||
if _, ok := groupMembersMap[(*memberCallbackResp.UserID)]; ok {
|
||||
if memberCallbackResp.MuteEndTime != nil {
|
||||
muteEndTimeTimestamp := *memberCallbackResp.MuteEndTime
|
||||
now := time.Now()
|
||||
nowUnixMilli := now.UnixMilli()
|
||||
|
||||
// 检查时间戳是否合理(防止时间戳单位错误导致自动禁言)
|
||||
// 如果时间戳小于1000000000000(2001-09-09),可能是秒级时间戳,需要转换为毫秒
|
||||
// 如果时间戳大于当前时间+10年,可能是时间戳单位错误
|
||||
var muteEndTime time.Time
|
||||
if muteEndTimeTimestamp < 1000000000000 {
|
||||
// 可能是秒级时间戳,转换为毫秒
|
||||
log.ZWarn(ctx, "webhookBeforeMembersJoinGroup: MuteEndTime appears to be in seconds, converting to milliseconds", nil,
|
||||
"groupID", groupID,
|
||||
"userID", *memberCallbackResp.UserID,
|
||||
"originalTimestamp", muteEndTimeTimestamp)
|
||||
muteEndTime = time.Unix(muteEndTimeTimestamp, 0)
|
||||
} else if muteEndTimeTimestamp > nowUnixMilli+10*365*24*3600*1000 {
|
||||
// 时间戳超过当前时间10年,可能是单位错误,忽略
|
||||
log.ZWarn(ctx, "webhookBeforeMembersJoinGroup: MuteEndTime is too far in the future, ignoring", nil,
|
||||
"groupID", groupID,
|
||||
"userID", *memberCallbackResp.UserID,
|
||||
"muteEndTimeTimestamp", muteEndTimeTimestamp,
|
||||
"nowUnixMilli", nowUnixMilli)
|
||||
continue
|
||||
} else {
|
||||
muteEndTime = time.UnixMilli(muteEndTimeTimestamp)
|
||||
}
|
||||
|
||||
// 记录webhook返回的禁言时间,用于排查自动禁言问题
|
||||
log.ZInfo(ctx, "webhookBeforeMembersJoinGroup: webhook returned MuteEndTime",
|
||||
"groupID", groupID,
|
||||
"userID", *memberCallbackResp.UserID,
|
||||
"muteEndTimeTimestamp", muteEndTimeTimestamp,
|
||||
"muteEndTime", muteEndTime.Format(time.RFC3339),
|
||||
"now", now.Format(time.RFC3339),
|
||||
"isMuted", muteEndTime.After(now),
|
||||
"mutedDurationSeconds", muteEndTime.Sub(now).Seconds())
|
||||
groupMembersMap[(*memberCallbackResp.UserID)].MuteEndTime = muteEndTime
|
||||
}
|
||||
|
||||
datautil.NotNilReplace(&groupMembersMap[(*memberCallbackResp.UserID)].FaceURL, memberCallbackResp.FaceURL)
|
||||
datautil.NotNilReplace(&groupMembersMap[(*memberCallbackResp.UserID)].Ex, memberCallbackResp.Ex)
|
||||
datautil.NotNilReplace(&groupMembersMap[(*memberCallbackResp.UserID)].Nickname, memberCallbackResp.Nickname)
|
||||
datautil.NotNilReplace(&groupMembersMap[(*memberCallbackResp.UserID)].RoleLevel, memberCallbackResp.RoleLevel)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupMemberInfo) error {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
cbReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand,
|
||||
GroupID: req.GroupID,
|
||||
UserID: req.UserID,
|
||||
}
|
||||
if req.Nickname != nil {
|
||||
cbReq.Nickname = &req.Nickname.Value
|
||||
}
|
||||
if req.FaceURL != nil {
|
||||
cbReq.FaceURL = &req.FaceURL.Value
|
||||
}
|
||||
if req.RoleLevel != nil {
|
||||
cbReq.RoleLevel = &req.RoleLevel.Value
|
||||
}
|
||||
if req.Ex != nil {
|
||||
cbReq.Ex = &req.Ex.Value
|
||||
}
|
||||
resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{}
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.FaceURL != nil {
|
||||
req.FaceURL = wrapperspb.String(*resp.FaceURL)
|
||||
}
|
||||
if resp.Nickname != nil {
|
||||
req.Nickname = wrapperspb.String(*resp.Nickname)
|
||||
}
|
||||
if resp.RoleLevel != nil {
|
||||
req.RoleLevel = wrapperspb.Int32(*resp.RoleLevel)
|
||||
}
|
||||
if resp.Ex != nil {
|
||||
req.Ex = wrapperspb.String(*resp.Ex)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterSetGroupMemberInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupMemberInfo) {
|
||||
cbReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterSetGroupMemberInfoCommand,
|
||||
GroupID: req.GroupID,
|
||||
UserID: req.UserID,
|
||||
}
|
||||
if req.Nickname != nil {
|
||||
cbReq.Nickname = &req.Nickname.Value
|
||||
}
|
||||
if req.FaceURL != nil {
|
||||
cbReq.FaceURL = &req.FaceURL.Value
|
||||
}
|
||||
if req.RoleLevel != nil {
|
||||
cbReq.RoleLevel = &req.RoleLevel.Value
|
||||
}
|
||||
if req.Ex != nil {
|
||||
cbReq.Ex = &req.Ex.Value
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterQuitGroup(ctx context.Context, after *config.AfterConfig, req *group.QuitGroupReq) {
|
||||
cbReq := &callbackstruct.CallbackQuitGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterQuitGroupCommand,
|
||||
GroupID: req.GroupID,
|
||||
UserID: req.UserID,
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackQuitGroupResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterKickGroupMember(ctx context.Context, after *config.AfterConfig, req *group.KickGroupMemberReq) {
|
||||
cbReq := &callbackstruct.CallbackKillGroupMemberReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterKickGroupCommand,
|
||||
GroupID: req.GroupID,
|
||||
KickedUserIDs: req.KickedUserIDs,
|
||||
Reason: req.Reason,
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackKillGroupMemberResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterDismissGroup(ctx context.Context, after *config.AfterConfig, req *callbackstruct.CallbackDisMissGroupReq) {
|
||||
req.CallbackCommand = callbackstruct.CallbackAfterDisMissGroupCommand
|
||||
g.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &callbackstruct.CallbackDisMissGroupResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeApplyJoinGroup(ctx context.Context, before *config.BeforeConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand
|
||||
resp := &callbackstruct.CallbackJoinGroupResp{}
|
||||
if err := g.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterTransferGroupOwner(ctx context.Context, after *config.AfterConfig, req *group.TransferGroupOwnerReq) {
|
||||
cbReq := &callbackstruct.CallbackTransferGroupOwnerReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterTransferGroupOwnerCommand,
|
||||
GroupID: req.GroupID,
|
||||
OldOwnerUserID: req.OldOwnerUserID,
|
||||
NewOwnerUserID: req.NewOwnerUserID,
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackTransferGroupOwnerResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before *config.BeforeConfig, req *group.InviteUserToGroupReq) (err error) {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
cbReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
GroupID: req.GroupID,
|
||||
Reason: req.Reason,
|
||||
InvitedUserIDs: req.InvitedUserIDs,
|
||||
}
|
||||
|
||||
resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{}
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle the scenario where certain members are refused
|
||||
// You might want to update the req.Members list or handle it as per your business logic
|
||||
|
||||
// if len(resp.RefusedMembersAccount) > 0 {
|
||||
// implement members are refused
|
||||
// }
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterJoinGroup(ctx context.Context, after *config.AfterConfig, req *group.JoinGroupReq) {
|
||||
cbReq := &callbackstruct.CallbackAfterJoinGroupReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterJoinGroupCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
GroupID: req.GroupID,
|
||||
ReqMessage: req.ReqMessage,
|
||||
JoinSource: req.JoinSource,
|
||||
InviterUserID: req.InviterUserID,
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterJoinGroupResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoReq) error {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
cbReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand,
|
||||
GroupID: req.GroupInfoForSet.GroupID,
|
||||
Notification: req.GroupInfoForSet.Notification,
|
||||
Introduction: req.GroupInfoForSet.Introduction,
|
||||
FaceURL: req.GroupInfoForSet.FaceURL,
|
||||
GroupName: req.GroupInfoForSet.GroupName,
|
||||
}
|
||||
if req.GroupInfoForSet.Ex != nil {
|
||||
cbReq.Ex = req.GroupInfoForSet.Ex.Value
|
||||
}
|
||||
log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfo", "ex", cbReq.Ex)
|
||||
if req.GroupInfoForSet.NeedVerification != nil {
|
||||
cbReq.NeedVerification = req.GroupInfoForSet.NeedVerification.Value
|
||||
}
|
||||
if req.GroupInfoForSet.LookMemberInfo != nil {
|
||||
cbReq.LookMemberInfo = req.GroupInfoForSet.LookMemberInfo.Value
|
||||
}
|
||||
if req.GroupInfoForSet.ApplyMemberFriend != nil {
|
||||
cbReq.ApplyMemberFriend = req.GroupInfoForSet.ApplyMemberFriend.Value
|
||||
}
|
||||
resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{}
|
||||
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Ex != nil {
|
||||
req.GroupInfoForSet.Ex = wrapperspb.String(*resp.Ex)
|
||||
}
|
||||
if resp.NeedVerification != nil {
|
||||
req.GroupInfoForSet.NeedVerification = wrapperspb.Int32(*resp.NeedVerification)
|
||||
}
|
||||
if resp.LookMemberInfo != nil {
|
||||
req.GroupInfoForSet.LookMemberInfo = wrapperspb.Int32(*resp.LookMemberInfo)
|
||||
}
|
||||
if resp.ApplyMemberFriend != nil {
|
||||
req.GroupInfoForSet.ApplyMemberFriend = wrapperspb.Int32(*resp.ApplyMemberFriend)
|
||||
}
|
||||
datautil.NotNilReplace(&req.GroupInfoForSet.GroupID, &resp.GroupID)
|
||||
datautil.NotNilReplace(&req.GroupInfoForSet.GroupName, &resp.GroupName)
|
||||
datautil.NotNilReplace(&req.GroupInfoForSet.FaceURL, &resp.FaceURL)
|
||||
datautil.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterSetGroupInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoReq) {
|
||||
cbReq := &callbackstruct.CallbackAfterSetGroupInfoReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoCommand,
|
||||
GroupID: req.GroupInfoForSet.GroupID,
|
||||
Notification: req.GroupInfoForSet.Notification,
|
||||
Introduction: req.GroupInfoForSet.Introduction,
|
||||
FaceURL: req.GroupInfoForSet.FaceURL,
|
||||
GroupName: req.GroupInfoForSet.GroupName,
|
||||
}
|
||||
if req.GroupInfoForSet.Ex != nil {
|
||||
cbReq.Ex = &req.GroupInfoForSet.Ex.Value
|
||||
}
|
||||
if req.GroupInfoForSet.NeedVerification != nil {
|
||||
cbReq.NeedVerification = &req.GroupInfoForSet.NeedVerification.Value
|
||||
}
|
||||
if req.GroupInfoForSet.LookMemberInfo != nil {
|
||||
cbReq.LookMemberInfo = &req.GroupInfoForSet.LookMemberInfo.Value
|
||||
}
|
||||
if req.GroupInfoForSet.ApplyMemberFriend != nil {
|
||||
cbReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value
|
||||
}
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoResp{}, after)
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookBeforeSetGroupInfoEx(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoExReq) error {
|
||||
return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
|
||||
cbReq := &callbackstruct.CallbackBeforeSetGroupInfoExReq{
|
||||
CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoExCommand,
|
||||
GroupID: req.GroupID,
|
||||
GroupName: req.GroupName,
|
||||
Notification: req.Notification,
|
||||
Introduction: req.Introduction,
|
||||
FaceURL: req.FaceURL,
|
||||
}
|
||||
|
||||
if req.Ex != nil {
|
||||
cbReq.Ex = req.Ex
|
||||
}
|
||||
log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfoEx", "ex", cbReq.Ex)
|
||||
|
||||
if req.NeedVerification != nil {
|
||||
cbReq.NeedVerification = req.NeedVerification
|
||||
}
|
||||
if req.LookMemberInfo != nil {
|
||||
cbReq.LookMemberInfo = req.LookMemberInfo
|
||||
}
|
||||
if req.ApplyMemberFriend != nil {
|
||||
cbReq.ApplyMemberFriend = req.ApplyMemberFriend
|
||||
}
|
||||
|
||||
resp := &callbackstruct.CallbackBeforeSetGroupInfoExResp{}
|
||||
|
||||
if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
datautil.NotNilReplace(&req.GroupID, &resp.GroupID)
|
||||
datautil.NotNilReplace(&req.GroupName, &resp.GroupName)
|
||||
datautil.NotNilReplace(&req.FaceURL, &resp.FaceURL)
|
||||
datautil.NotNilReplace(&req.Introduction, &resp.Introduction)
|
||||
datautil.NotNilReplace(&req.Ex, &resp.Ex)
|
||||
datautil.NotNilReplace(&req.NeedVerification, &resp.NeedVerification)
|
||||
datautil.NotNilReplace(&req.LookMemberInfo, &resp.LookMemberInfo)
|
||||
datautil.NotNilReplace(&req.ApplyMemberFriend, &resp.ApplyMemberFriend)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (g *groupServer) webhookAfterSetGroupInfoEx(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoExReq) {
|
||||
cbReq := &callbackstruct.CallbackAfterSetGroupInfoExReq{
|
||||
CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoExCommand,
|
||||
GroupID: req.GroupID,
|
||||
GroupName: req.GroupName,
|
||||
Notification: req.Notification,
|
||||
Introduction: req.Introduction,
|
||||
FaceURL: req.FaceURL,
|
||||
}
|
||||
|
||||
if req.Ex != nil {
|
||||
cbReq.Ex = req.Ex
|
||||
}
|
||||
if req.NeedVerification != nil {
|
||||
cbReq.NeedVerification = req.NeedVerification
|
||||
}
|
||||
if req.LookMemberInfo != nil {
|
||||
cbReq.LookMemberInfo = req.LookMemberInfo
|
||||
}
|
||||
if req.ApplyMemberFriend != nil {
|
||||
cbReq.ApplyMemberFriend = req.ApplyMemberFriend
|
||||
}
|
||||
|
||||
g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoExResp{}, after)
|
||||
}
|
||||
63
internal/rpc/group/convert.go
Normal file
63
internal/rpc/group/convert.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
|
||||
"git.imall.cloud/openim/protocol/sdkws"
|
||||
)
|
||||
|
||||
func (g *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
|
||||
return &sdkws.GroupInfo{
|
||||
GroupID: group.GroupID,
|
||||
GroupName: group.GroupName,
|
||||
Notification: group.Notification,
|
||||
Introduction: group.Introduction,
|
||||
FaceURL: group.FaceURL,
|
||||
OwnerUserID: ownerUserID,
|
||||
CreateTime: group.CreateTime.UnixMilli(),
|
||||
MemberCount: memberCount,
|
||||
Ex: group.Ex,
|
||||
Status: group.Status,
|
||||
CreatorUserID: group.CreatorUserID,
|
||||
GroupType: group.GroupType,
|
||||
NeedVerification: group.NeedVerification,
|
||||
LookMemberInfo: group.LookMemberInfo,
|
||||
ApplyMemberFriend: group.ApplyMemberFriend,
|
||||
NotificationUpdateTime: group.NotificationUpdateTime.UnixMilli(),
|
||||
NotificationUserID: group.NotificationUserID,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
|
||||
return &sdkws.GroupMemberFullInfo{
|
||||
GroupID: member.GroupID,
|
||||
UserID: member.UserID,
|
||||
RoleLevel: member.RoleLevel,
|
||||
JoinTime: member.JoinTime.UnixMilli(),
|
||||
Nickname: member.Nickname,
|
||||
FaceURL: member.FaceURL,
|
||||
AppMangerLevel: appMangerLevel,
|
||||
JoinSource: member.JoinSource,
|
||||
OperatorUserID: member.OperatorUserID,
|
||||
Ex: member.Ex,
|
||||
MuteEndTime: member.MuteEndTime.UnixMilli(),
|
||||
InviterUserID: member.InviterUserID,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *groupServer) groupMemberDB2PB2(member *model.GroupMember) *sdkws.GroupMemberFullInfo {
|
||||
return g.groupMemberDB2PB(member, 0)
|
||||
}
|
||||
134
internal/rpc/group/db_map.go
Normal file
134
internal/rpc/group/db_map.go
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pbgroup "git.imall.cloud/openim/protocol/group"
|
||||
"git.imall.cloud/openim/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
)
|
||||
|
||||
func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any {
|
||||
m := make(map[string]any)
|
||||
if group.GroupName != "" {
|
||||
m["group_name"] = group.GroupName
|
||||
}
|
||||
if group.Notification != "" {
|
||||
m["notification"] = group.Notification
|
||||
m["notification_update_time"] = time.Now()
|
||||
m["notification_user_id"] = mcontext.GetOpUserID(ctx)
|
||||
}
|
||||
if group.Introduction != "" {
|
||||
m["introduction"] = group.Introduction
|
||||
}
|
||||
if group.FaceURL != "" {
|
||||
m["face_url"] = group.FaceURL
|
||||
}
|
||||
if group.NeedVerification != nil {
|
||||
m["need_verification"] = group.NeedVerification.Value
|
||||
}
|
||||
if group.LookMemberInfo != nil {
|
||||
m["look_member_info"] = group.LookMemberInfo.Value
|
||||
}
|
||||
if group.ApplyMemberFriend != nil {
|
||||
m["apply_member_friend"] = group.ApplyMemberFriend.Value
|
||||
}
|
||||
if group.Ex != nil {
|
||||
m["ex"] = group.Ex.Value
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func UpdateGroupInfoExMap(ctx context.Context, group *pbgroup.SetGroupInfoExReq) (m map[string]any, normalFlag, groupNameFlag, notificationFlag bool, err error) {
|
||||
m = make(map[string]any)
|
||||
|
||||
if group.GroupName != nil {
|
||||
if strings.TrimSpace(group.GroupName.Value) != "" {
|
||||
m["group_name"] = group.GroupName.Value
|
||||
groupNameFlag = true
|
||||
} else {
|
||||
return nil, normalFlag, notificationFlag, groupNameFlag, errs.ErrArgs.WrapMsg("group name is empty")
|
||||
}
|
||||
}
|
||||
|
||||
if group.Notification != nil {
|
||||
notificationFlag = true
|
||||
group.Notification.Value = strings.TrimSpace(group.Notification.Value) // if Notification only contains spaces, set it to empty string
|
||||
|
||||
m["notification"] = group.Notification.Value
|
||||
m["notification_user_id"] = mcontext.GetOpUserID(ctx)
|
||||
m["notification_update_time"] = time.Now()
|
||||
}
|
||||
if group.Introduction != nil {
|
||||
m["introduction"] = group.Introduction.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.FaceURL != nil {
|
||||
m["face_url"] = group.FaceURL.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.NeedVerification != nil {
|
||||
m["need_verification"] = group.NeedVerification.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.LookMemberInfo != nil {
|
||||
m["look_member_info"] = group.LookMemberInfo.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.ApplyMemberFriend != nil {
|
||||
m["apply_member_friend"] = group.ApplyMemberFriend.Value
|
||||
normalFlag = true
|
||||
}
|
||||
if group.Ex != nil {
|
||||
m["ex"] = group.Ex.Value
|
||||
normalFlag = true
|
||||
}
|
||||
|
||||
return m, normalFlag, groupNameFlag, notificationFlag, nil
|
||||
}
|
||||
|
||||
func UpdateGroupStatusMap(status int) map[string]any {
|
||||
return map[string]any{
|
||||
"status": status,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateGroupMemberMutedTimeMap(t time.Time) map[string]any {
|
||||
return map[string]any{
|
||||
"mute_end_time": t,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateGroupMemberMap(req *pbgroup.SetGroupMemberInfo) map[string]any {
|
||||
m := make(map[string]any)
|
||||
if req.Nickname != nil {
|
||||
m["nickname"] = req.Nickname.Value
|
||||
}
|
||||
if req.FaceURL != nil {
|
||||
m["face_url"] = req.FaceURL.Value
|
||||
}
|
||||
if req.RoleLevel != nil {
|
||||
m["role_level"] = req.RoleLevel.Value
|
||||
}
|
||||
if req.Ex != nil {
|
||||
m["ex"] = req.Ex.Value
|
||||
}
|
||||
return m
|
||||
}
|
||||
25
internal/rpc/group/fill.go
Normal file
25
internal/rpc/group/fill.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
relationtb "git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
|
||||
)
|
||||
|
||||
func (g *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMember) error {
|
||||
return g.notification.PopulateGroupMember(ctx, members...)
|
||||
}
|
||||
2096
internal/rpc/group/group.go
Normal file
2096
internal/rpc/group/group.go
Normal file
File diff suppressed because it is too large
Load Diff
930
internal/rpc/group/notification.go
Normal file
930
internal/rpc/group/notification.go
Normal file
@@ -0,0 +1,930 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/rpcli"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/authverify"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/convert"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/servererrs"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/controller"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/database"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/versionctx"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/msgprocessor"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/notification"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/notification/common_user"
|
||||
"git.imall.cloud/openim/protocol/constant"
|
||||
pbgroup "git.imall.cloud/openim/protocol/group"
|
||||
"git.imall.cloud/openim/protocol/msg"
|
||||
"git.imall.cloud/openim/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
)
|
||||
|
||||
// GroupApplicationReceiver
|
||||
const (
|
||||
applicantReceiver = iota
|
||||
adminReceiver
|
||||
)
|
||||
|
||||
func NewNotificationSender(db controller.GroupDatabase, config *Config, userClient *rpcli.UserClient, msgClient *rpcli.MsgClient, conversationClient *rpcli.ConversationClient) *NotificationSender {
|
||||
return &NotificationSender{
|
||||
NotificationSender: notification.NewNotificationSender(&config.NotificationConfig,
|
||||
notification.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
|
||||
return msgClient.SendMsg(ctx, req)
|
||||
}),
|
||||
notification.WithUserRpcClient(userClient.GetUserInfo),
|
||||
),
|
||||
getUsersInfo: func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error) {
|
||||
users, err := userClient.GetUsersInfo(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return datautil.Slice(users, func(e *sdkws.UserInfo) common_user.CommonUser { return e }), nil
|
||||
},
|
||||
db: db,
|
||||
config: config,
|
||||
msgClient: msgClient,
|
||||
conversationClient: conversationClient,
|
||||
}
|
||||
}
|
||||
|
||||
type NotificationSender struct {
|
||||
*notification.NotificationSender
|
||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
|
||||
db controller.GroupDatabase
|
||||
config *Config
|
||||
msgClient *rpcli.MsgClient
|
||||
conversationClient *rpcli.ConversationClient
|
||||
}
|
||||
|
||||
func (g *NotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error {
|
||||
if len(members) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 收集所有需要填充用户信息的UserID
|
||||
userIDsMap := make(map[string]struct{})
|
||||
for _, member := range members {
|
||||
userIDsMap[member.UserID] = struct{}{}
|
||||
}
|
||||
|
||||
// 获取所有用户信息
|
||||
users, err := g.getUsersInfo(ctx, datautil.Keys(userIDsMap))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 构建用户信息map
|
||||
userMap := make(map[string]common_user.CommonUser)
|
||||
for i, user := range users {
|
||||
userMap[user.GetUserID()] = users[i]
|
||||
}
|
||||
|
||||
// 填充群成员信息
|
||||
for i, member := range members {
|
||||
user, ok := userMap[member.UserID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 填充昵称和头像
|
||||
if member.Nickname == "" {
|
||||
members[i].Nickname = user.GetNickname()
|
||||
}
|
||||
if member.FaceURL == "" {
|
||||
members[i].FaceURL = user.GetFaceURL()
|
||||
}
|
||||
|
||||
// 填充UserType和UserFlag到Ex字段
|
||||
// 先解析现有的Ex字段(如果有的话)
|
||||
var exData map[string]interface{}
|
||||
if members[i].Ex != "" {
|
||||
_ = jsonutil.JsonUnmarshal([]byte(members[i].Ex), &exData)
|
||||
}
|
||||
if exData == nil {
|
||||
exData = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// 添加userType和userFlag
|
||||
exData["userType"] = user.GetUserType()
|
||||
exData["userFlag"] = user.GetUserFlag()
|
||||
|
||||
exJSON, _ := jsonutil.JsonMarshal(exData)
|
||||
members[i].Ex = string(exJSON)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
|
||||
users, err := g.getUsersInfo(ctx, []string{userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return nil, servererrs.ErrUserIDNotFound.WrapMsg(fmt.Sprintf("user %s not found", userID))
|
||||
}
|
||||
return &sdkws.PublicUserInfo{
|
||||
UserID: users[0].GetUserID(),
|
||||
Nickname: users[0].GetNickname(),
|
||||
FaceURL: users[0].GetFaceURL(),
|
||||
Ex: users[0].GetEx(),
|
||||
UserType: users[0].GetUserType(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
|
||||
gm, err := g.db.TakeGroup(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
num, err := g.db.FindGroupMemberNum(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ownerUserIDs, err := g.db.GetGroupRoleLevelMemberIDs(ctx, groupID, constant.GroupOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ownerUserID string
|
||||
if len(ownerUserIDs) > 0 {
|
||||
ownerUserID = ownerUserIDs[0]
|
||||
}
|
||||
|
||||
return convert.Db2PbGroupInfo(gm, ownerUserID, num), nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
||||
members, err := g.db.FindGroupMembers(ctx, groupID, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.ZDebug(ctx, "getGroupMembers", "members", members)
|
||||
res := make([]*sdkws.GroupMemberFullInfo, 0, len(members))
|
||||
for _, member := range members {
|
||||
res = append(res, g.groupMemberDB2PB(member, 0))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupMemberMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) {
|
||||
members, err := g.getGroupMembers(ctx, groupID, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[string]*sdkws.GroupMemberFullInfo)
|
||||
for i, member := range members {
|
||||
m[member.UserID] = members[i]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupMember(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) {
|
||||
members, err := g.getGroupMembers(ctx, groupID, []string{userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(members) == 0 {
|
||||
return nil, errs.ErrInternalServer.WrapMsg(fmt.Sprintf("group %s member %s not found", groupID, userID))
|
||||
}
|
||||
return members[0], nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) {
|
||||
members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := g.PopulateGroupMember(ctx, members...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fn := func(e *model.GroupMember) string { return e.UserID }
|
||||
return datautil.Slice(members, fn), nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
|
||||
return &sdkws.GroupMemberFullInfo{
|
||||
GroupID: member.GroupID,
|
||||
UserID: member.UserID,
|
||||
RoleLevel: member.RoleLevel,
|
||||
JoinTime: member.JoinTime.UnixMilli(),
|
||||
Nickname: member.Nickname,
|
||||
FaceURL: member.FaceURL,
|
||||
AppMangerLevel: appMangerLevel,
|
||||
JoinSource: member.JoinSource,
|
||||
OperatorUserID: member.OperatorUserID,
|
||||
Ex: member.Ex,
|
||||
MuteEndTime: member.MuteEndTime.UnixMilli(),
|
||||
InviterUserID: member.InviterUserID,
|
||||
}
|
||||
}
|
||||
|
||||
/* func (g *NotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
|
||||
users, err := g.getUsersInfo(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make(map[string]*sdkws.UserInfo)
|
||||
for _, user := range users {
|
||||
result[user.GetUserID()] = user.(*sdkws.UserInfo)
|
||||
}
|
||||
return result, nil
|
||||
} */
|
||||
|
||||
func (g *NotificationSender) fillOpUser(ctx context.Context, targetUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
|
||||
return g.fillUserByUserID(ctx, mcontext.GetOpUserID(ctx), targetUser, groupID)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) fillUserByUserID(ctx context.Context, userID string, targetUser **sdkws.GroupMemberFullInfo, groupID string) error {
|
||||
if targetUser == nil {
|
||||
return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil")
|
||||
}
|
||||
if groupID != "" {
|
||||
if authverify.CheckUserIsAdmin(ctx, userID) {
|
||||
*targetUser = &sdkws.GroupMemberFullInfo{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
RoleLevel: constant.GroupAdmin,
|
||||
AppMangerLevel: constant.AppAdmin,
|
||||
}
|
||||
} else {
|
||||
member, err := g.db.TakeGroupMember(ctx, groupID, userID)
|
||||
if err == nil {
|
||||
*targetUser = g.groupMemberDB2PB(member, 0)
|
||||
} else if !(errors.Is(err, mongo.ErrNoDocuments) || errs.ErrRecordNotFound.Is(err)) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
user, err := g.getUser(ctx, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *targetUser == nil {
|
||||
*targetUser = &sdkws.GroupMemberFullInfo{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
Nickname: user.Nickname,
|
||||
FaceURL: user.FaceURL,
|
||||
OperatorUserID: userID,
|
||||
}
|
||||
} else {
|
||||
if (*targetUser).Nickname == "" {
|
||||
(*targetUser).Nickname = user.Nickname
|
||||
}
|
||||
if (*targetUser).FaceURL == "" {
|
||||
(*targetUser).FaceURL = user.FaceURL
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) {
|
||||
versions := versionctx.GetVersionLog(ctx).Get()
|
||||
for i := len(versions) - 1; i >= 0; i-- {
|
||||
coll := versions[i]
|
||||
if coll.Name == collName && coll.Doc.DID == id {
|
||||
*version = uint64(coll.Doc.Version)
|
||||
*versionID = coll.Doc.ID.Hex()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) setSortVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string, sortVersion *uint64) {
|
||||
versions := versionctx.GetVersionLog(ctx).Get()
|
||||
for _, coll := range versions {
|
||||
if coll.Name == collName && coll.Doc.DID == id {
|
||||
*version = uint64(coll.Doc.Version)
|
||||
*versionID = coll.Doc.ID.Hex()
|
||||
for _, elem := range coll.Doc.Logs {
|
||||
if elem.EID == model.VersionSortChangeID {
|
||||
*sortVersion = uint64(elem.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips, SendMessage *bool) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, notification.WithRpcGetUserName())
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips, sendMessage *bool) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, notification.WithRpcGetUserName(), notification.WithSendMessage(sendMessage))
|
||||
}
|
||||
|
||||
func (g *NotificationSender) uuid() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
func (g *NotificationSender) getGroupRequest(ctx context.Context, groupID string, userID string) (*sdkws.GroupRequest, error) {
|
||||
request, err := g.db.TakeGroupRequest(ctx, groupID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users, err := g.getUsersInfo(ctx, []string{userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return nil, servererrs.ErrUserIDNotFound.WrapMsg(fmt.Sprintf("user %s not found", userID))
|
||||
}
|
||||
info, ok := users[0].(*sdkws.UserInfo)
|
||||
if !ok {
|
||||
info = &sdkws.UserInfo{
|
||||
UserID: users[0].GetUserID(),
|
||||
Nickname: users[0].GetNickname(),
|
||||
FaceURL: users[0].GetFaceURL(),
|
||||
Ex: users[0].GetEx(),
|
||||
}
|
||||
}
|
||||
return convert.Db2PbGroupRequest(request, info, nil), nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq, dbReq *model.GroupRequest) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
request, err := g.getGroupRequest(ctx, dbReq.GroupID, dbReq.UserID)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "JoinGroupApplicationNotification getGroupRequest", err, "dbReq", dbReq)
|
||||
return
|
||||
}
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var user *sdkws.PublicUserInfo
|
||||
user, err = g.getUser(ctx, req.InviterUserID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userIDs, err := g.getGroupOwnerAndAdminUserID(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userIDs = append(userIDs, req.InviterUserID, mcontext.GetOpUserID(ctx))
|
||||
tips := &sdkws.JoinGroupApplicationTips{
|
||||
Group: group,
|
||||
Applicant: user,
|
||||
ReqMsg: req.ReqMessage,
|
||||
Uuid: g.uuid(),
|
||||
Request: request,
|
||||
}
|
||||
for _, userID := range datautil.Distinct(userIDs) {
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.JoinGroupApplicationNotification, tips)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, member.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.MemberQuitTips{Group: group, QuitUser: member}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, member.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
request, err := g.getGroupRequest(ctx, req.GroupID, req.FromUserID)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GroupApplicationAcceptedNotification getGroupRequest", err, "req", req)
|
||||
return
|
||||
}
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var userIDs []string
|
||||
userIDs, err = g.getGroupOwnerAndAdminUserID(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var opUser *sdkws.GroupMemberFullInfo
|
||||
if err = g.fillOpUser(ctx, &opUser, group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupApplicationAcceptedTips{
|
||||
Group: group,
|
||||
OpUser: opUser,
|
||||
HandleMsg: req.HandledMsg,
|
||||
Uuid: g.uuid(),
|
||||
Request: request,
|
||||
}
|
||||
for _, userID := range append(userIDs, req.FromUserID) {
|
||||
if userID == req.FromUserID {
|
||||
tips.ReceiverAs = applicantReceiver
|
||||
} else {
|
||||
tips.ReceiverAs = adminReceiver
|
||||
}
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationAcceptedNotification, tips)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
request, err := g.getGroupRequest(ctx, req.GroupID, req.FromUserID)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GroupApplicationAcceptedNotification getGroupRequest", err, "req", req)
|
||||
return
|
||||
}
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var userIDs []string
|
||||
userIDs, err = g.getGroupOwnerAndAdminUserID(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var opUser *sdkws.GroupMemberFullInfo
|
||||
if err = g.fillOpUser(ctx, &opUser, group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupApplicationRejectedTips{
|
||||
Group: group,
|
||||
OpUser: opUser,
|
||||
HandleMsg: req.HandledMsg,
|
||||
Uuid: g.uuid(),
|
||||
Request: request,
|
||||
}
|
||||
for _, userID := range append(userIDs, req.FromUserID) {
|
||||
if userID == req.FromUserID {
|
||||
tips.ReceiverAs = applicantReceiver
|
||||
} else {
|
||||
tips.ReceiverAs = adminReceiver
|
||||
}
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), userID, constant.GroupApplicationRejectedNotification, tips)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
var member map[string]*sdkws.GroupMemberFullInfo
|
||||
member, err = g.getGroupMemberMap(ctx, req.GroupID, []string{opUserID, req.NewOwnerUserID, req.OldOwnerUserID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupOwnerTransferredTips{
|
||||
Group: group,
|
||||
OpUser: member[opUserID],
|
||||
NewGroupOwner: member[req.NewOwnerUserID],
|
||||
OldGroupOwnerInfo: member[req.OldOwnerUserID],
|
||||
}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, req.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips, SendMessage *bool) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, SendMessage *bool, invitedOpUserID string, entrantUserID ...string) error {
|
||||
return g.groupApplicationAgreeMemberEnterNotification(ctx, groupID, SendMessage, invitedOpUserID, entrantUserID...)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) groupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, SendMessage *bool, invitedOpUserID string, entrantUserID ...string) error {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||
maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, entrantUserID, maxSeq+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, entrantUserID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
users, err := g.getGroupMembers(ctx, groupID, entrantUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tips := &sdkws.MemberInvitedTips{
|
||||
Group: group,
|
||||
InvitedUserList: users,
|
||||
}
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
if err = g.fillUserByUserID(ctx, opUserID, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return nil
|
||||
}
|
||||
if invitedOpUserID == opUserID {
|
||||
tips.InviterUser = tips.OpUser
|
||||
} else {
|
||||
if err = g.fillUserByUserID(ctx, invitedOpUserID, &tips.InviterUser, tips.Group.GroupID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) error {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if !g.config.RpcConfig.EnableHistoryForNewMembers {
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||
maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, []string{entrantUserID}, maxSeq+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, []string{entrantUserID}); err != nil {
|
||||
return err
|
||||
}
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tips := &sdkws.MemberEnterTips{
|
||||
Group: group,
|
||||
EntrantUser: user,
|
||||
OperationTime: time.Now().UnixMilli(),
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
// 群内广播:通知所有群成员有人入群
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips)
|
||||
// 给入群本人发送一条系统通知(单聊),便于客户端展示“你已加入群聊”
|
||||
g.NotificationWithSessionType(ctx, mcontext.GetOpUserID(ctx), entrantUserID,
|
||||
constant.MemberEnterNotification, constant.SingleChatType, tips)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips, SendMessage *bool) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips, notification.WithSendMessage(SendMessage))
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
log.ZDebug(ctx, "GroupMemberMutedNotification start", "groupID", groupID, "groupMemberUserID", groupMemberUserID, "mutedSeconds", mutedSeconds, "opUserID", mcontext.GetOpUserID(ctx))
|
||||
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberMutedNotification getGroupInfo failed", err, "groupID", groupID)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "GroupMemberMutedNotification got group info", "groupID", groupID, "groupName", group.GroupName)
|
||||
|
||||
var user map[string]*sdkws.GroupMemberFullInfo
|
||||
user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberMutedNotification getGroupMemberMap failed", err, "groupID", groupID)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "GroupMemberMutedNotification got user map", "opUser", user[mcontext.GetOpUserID(ctx)], "mutedUser", user[groupMemberUserID])
|
||||
|
||||
tips := &sdkws.GroupMemberMutedTips{
|
||||
Group: group, MutedSeconds: mutedSeconds,
|
||||
OpUser: user[mcontext.GetOpUserID(ctx)], MutedUser: user[groupMemberUserID],
|
||||
}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberMutedNotification fillOpUser failed", err)
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
// 在群聊中通知,但推送服务会过滤只推送给群主、管理员和被禁言成员本人
|
||||
log.ZInfo(ctx, "GroupMemberMutedNotification sending notification", "groupID", groupID, "recvID", group.GroupID, "contentType", constant.GroupMemberMutedNotification, "mutedUserID", groupMemberUserID, "mutedSeconds", mutedSeconds)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips)
|
||||
log.ZDebug(ctx, "GroupMemberMutedNotification notification sent", "groupID", groupID)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
log.ZDebug(ctx, "GroupMemberCancelMutedNotification start", "groupID", groupID, "groupMemberUserID", groupMemberUserID, "opUserID", mcontext.GetOpUserID(ctx))
|
||||
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberCancelMutedNotification getGroupInfo failed", err, "groupID", groupID)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "GroupMemberCancelMutedNotification got group info", "groupID", groupID, "groupName", group.GroupName)
|
||||
|
||||
var user map[string]*sdkws.GroupMemberFullInfo
|
||||
user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberCancelMutedNotification getGroupMemberMap failed", err, "groupID", groupID)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "GroupMemberCancelMutedNotification got user map", "opUser", user[mcontext.GetOpUserID(ctx)], "mutedUser", user[groupMemberUserID])
|
||||
|
||||
tips := &sdkws.GroupMemberCancelMutedTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], MutedUser: user[groupMemberUserID]}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
log.ZWarn(ctx, "GroupMemberCancelMutedNotification fillOpUser failed", err)
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID)
|
||||
// 在群聊中通知,但推送服务会过滤只推送给群主、管理员和被取消禁言成员本人
|
||||
log.ZInfo(ctx, "GroupMemberCancelMutedNotification sending notification", "groupID", groupID, "recvID", group.GroupID, "contentType", constant.GroupMemberCancelMutedNotification, "cancelMutedUserID", groupMemberUserID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips)
|
||||
log.ZDebug(ctx, "GroupMemberCancelMutedNotification notification sent", "groupID", groupID)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMutedNotification(ctx context.Context, groupID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var users []*sdkws.GroupMemberFullInfo
|
||||
users, err = g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupMutedTips{Group: group}
|
||||
if len(users) > 0 {
|
||||
tips.OpUser = users[0]
|
||||
}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, groupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var users []*sdkws.GroupMemberFullInfo
|
||||
users, err = g.getGroupMembers(ctx, groupID, []string{mcontext.GetOpUserID(ctx)})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupCancelMutedTips{Group: group}
|
||||
if len(users) > 0 {
|
||||
tips.OpUser = users[0]
|
||||
}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, groupID)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var user map[string]*sdkws.GroupMemberFullInfo
|
||||
user, err = g.getGroupMemberMap(ctx, groupID, []string{groupMemberUserID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
user, err := g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||
var err error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.ZError(ctx, stringutil.GetFuncName(1)+" failed", err)
|
||||
}
|
||||
}()
|
||||
var group *sdkws.GroupInfo
|
||||
group, err = g.getGroupInfo(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var user map[string]*sdkws.GroupMemberFullInfo
|
||||
user, err = g.getGroupMemberMap(ctx, groupID, []string{mcontext.GetOpUserID(ctx), groupMemberUserID})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupMemberInfoSetTips{Group: group, OpUser: user[mcontext.GetOpUserID(ctx)], ChangedUser: user[groupMemberUserID]}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
|
||||
return
|
||||
}
|
||||
g.setSortVersion(ctx, &tips.GroupMemberVersion, &tips.GroupMemberVersionID, database.GroupMemberVersionName, tips.Group.GroupID, &tips.GroupSortVersion)
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips)
|
||||
}
|
||||
47
internal/rpc/group/statistics.go
Normal file
47
internal/rpc/group/statistics.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/authverify"
|
||||
"git.imall.cloud/openim/protocol/group"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
func (g *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCreateCountReq) (*group.GroupCreateCountResp, error) {
|
||||
if req.Start > req.End {
|
||||
return nil, errs.ErrArgs.WrapMsg("start > end: %d > %d", req.Start, req.End)
|
||||
}
|
||||
if err := authverify.CheckAdmin(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
total, err := g.db.CountTotal(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
start := time.UnixMilli(req.Start)
|
||||
before, err := g.db.CountTotal(ctx, &start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count, err := g.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &group.GroupCreateCountResp{Total: total, Before: before, Count: count}, nil
|
||||
}
|
||||
197
internal/rpc/group/sync.go
Normal file
197
internal/rpc/group/sync.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package group
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.imall.cloud/openim/open-im-server-deploy/internal/rpc/incrversion"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/authverify"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/servererrs"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
|
||||
"git.imall.cloud/openim/open-im-server-deploy/pkg/util/hashutil"
|
||||
"git.imall.cloud/openim/protocol/constant"
|
||||
pbgroup "git.imall.cloud/openim/protocol/group"
|
||||
"git.imall.cloud/openim/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
const versionSyncLimit = 500
|
||||
|
||||
func (g *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) {
|
||||
userIDs, err := g.db.FindGroupMemberUserID(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := authverify.CheckAccessIn(ctx, userIDs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vl, err := g.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idHash := hashutil.IdHash(userIDs)
|
||||
if req.IdHash == idHash {
|
||||
userIDs = nil
|
||||
}
|
||||
return &pbgroup.GetFullGroupMemberUserIDsResp{
|
||||
Version: idHash,
|
||||
VersionID: vl.ID.Hex(),
|
||||
Equal: req.IdHash == idHash,
|
||||
UserIDs: userIDs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *groupServer) GetFullJoinGroupIDs(ctx context.Context, req *pbgroup.GetFullJoinGroupIDsReq) (*pbgroup.GetFullJoinGroupIDsResp, error) {
|
||||
if err := authverify.CheckAccess(ctx, req.UserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vl, err := g.db.FindMaxJoinGroupVersionCache(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupIDs, err := g.db.FindJoinGroupID(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idHash := hashutil.IdHash(groupIDs)
|
||||
if req.IdHash == idHash {
|
||||
groupIDs = nil
|
||||
}
|
||||
return &pbgroup.GetFullJoinGroupIDsResp{
|
||||
Version: idHash,
|
||||
VersionID: vl.ID.Hex(),
|
||||
Equal: req.IdHash == idHash,
|
||||
GroupIDs: groupIDs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgroup.GetIncrementalGroupMemberReq) (*pbgroup.GetIncrementalGroupMemberResp, error) {
|
||||
if err := g.checkAdminOrInGroup(ctx, req.GroupID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
group, err := g.db.TakeGroup(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if group.Status == constant.GroupStatusDismissed {
|
||||
return nil, servererrs.ErrDismissedAlready.Wrap()
|
||||
}
|
||||
var (
|
||||
hasGroupUpdate bool
|
||||
sortVersion uint64
|
||||
)
|
||||
opt := incrversion.Option[*sdkws.GroupMemberFullInfo, pbgroup.GetIncrementalGroupMemberResp]{
|
||||
Ctx: ctx,
|
||||
VersionKey: req.GroupID,
|
||||
VersionID: req.VersionID,
|
||||
VersionNumber: req.Version,
|
||||
Version: func(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) {
|
||||
vl, err := g.db.FindMemberIncrVersion(ctx, groupID, version, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logs := make([]model.VersionLogElem, 0, len(vl.Logs))
|
||||
for i, log := range vl.Logs {
|
||||
switch log.EID {
|
||||
case model.VersionGroupChangeID:
|
||||
vl.LogLen--
|
||||
hasGroupUpdate = true
|
||||
case model.VersionSortChangeID:
|
||||
vl.LogLen--
|
||||
sortVersion = uint64(log.Version)
|
||||
default:
|
||||
logs = append(logs, vl.Logs[i])
|
||||
}
|
||||
}
|
||||
vl.Logs = logs
|
||||
if vl.LogLen > 0 {
|
||||
hasGroupUpdate = true
|
||||
}
|
||||
return vl, nil
|
||||
},
|
||||
CacheMaxVersion: g.db.FindMaxGroupMemberVersionCache,
|
||||
Find: func(ctx context.Context, ids []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
||||
return g.getGroupMembersInfo(ctx, req.GroupID, ids)
|
||||
},
|
||||
Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupMemberFullInfo, full bool) *pbgroup.GetIncrementalGroupMemberResp {
|
||||
return &pbgroup.GetIncrementalGroupMemberResp{
|
||||
VersionID: version.ID.Hex(),
|
||||
Version: uint64(version.Version),
|
||||
Full: full,
|
||||
Delete: delIDs,
|
||||
Insert: insertList,
|
||||
Update: updateList,
|
||||
SortVersion: sortVersion,
|
||||
}
|
||||
},
|
||||
}
|
||||
resp, err := opt.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Full || hasGroupUpdate {
|
||||
count, err := g.db.FindGroupMemberNum(ctx, group.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
owner, err := g.db.TakeGroupOwner(ctx, group.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Group = g.groupDB2PB(group, owner.UserID, count)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (g *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) {
|
||||
if err := authverify.CheckAccess(ctx, req.UserID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opt := incrversion.Option[*sdkws.GroupInfo, pbgroup.GetIncrementalJoinGroupResp]{
|
||||
Ctx: ctx,
|
||||
VersionKey: req.UserID,
|
||||
VersionID: req.VersionID,
|
||||
VersionNumber: req.Version,
|
||||
Version: g.db.FindJoinIncrVersion,
|
||||
CacheMaxVersion: g.db.FindMaxJoinGroupVersionCache,
|
||||
Find: g.getGroupsInfo,
|
||||
Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupInfo, full bool) *pbgroup.GetIncrementalJoinGroupResp {
|
||||
return &pbgroup.GetIncrementalJoinGroupResp{
|
||||
VersionID: version.ID.Hex(),
|
||||
Version: uint64(version.Version),
|
||||
Full: full,
|
||||
Delete: delIDs,
|
||||
Insert: insertList,
|
||||
Update: updateList,
|
||||
}
|
||||
},
|
||||
}
|
||||
return opt.Build()
|
||||
}
|
||||
|
||||
func (g *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *pbgroup.BatchGetIncrementalGroupMemberReq) (*pbgroup.BatchGetIncrementalGroupMemberResp, error) {
|
||||
var num int
|
||||
resp := make(map[string]*pbgroup.GetIncrementalGroupMemberResp)
|
||||
|
||||
for _, memberReq := range req.ReqList {
|
||||
if _, ok := resp[memberReq.GroupID]; ok {
|
||||
continue
|
||||
}
|
||||
memberResp, err := g.GetIncrementalGroupMember(ctx, memberReq)
|
||||
if err != nil {
|
||||
if errors.Is(err, servererrs.ErrDismissedAlready) {
|
||||
log.ZWarn(ctx, "Failed to get incremental group member", err, "groupID", memberReq.GroupID, "request", memberReq)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp[memberReq.GroupID] = memberResp
|
||||
num += len(memberResp.Insert) + len(memberResp.Update) + len(memberResp.Delete)
|
||||
if num >= versionSyncLimit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &pbgroup.BatchGetIncrementalGroupMemberResp{RespList: resp}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user