Merge: main

pull/2997/head
icey-yu 9 months ago
commit 5cc018df7d

@ -2,8 +2,6 @@ module github.com/openimsdk/open-im-server/v3
go 1.22.7 go 1.22.7
toolchain go1.23.2
require ( require (
firebase.google.com/go/v4 v4.14.1 firebase.google.com/go/v4 v4.14.1
github.com/dtm-labs/rockscache v0.1.1 github.com/dtm-labs/rockscache v0.1.1
@ -14,8 +12,8 @@ require (
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.1
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/openimsdk/protocol v0.0.72-alpha.66 github.com/openimsdk/protocol v0.0.72-alpha.68
github.com/openimsdk/tools v0.0.50-alpha.57 github.com/openimsdk/tools v0.0.50-alpha.60
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_golang v1.18.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0

@ -347,10 +347,10 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
github.com/openimsdk/gomake v0.0.15-alpha.2 h1:5Q8yl8ezy2yx+q8/ucU/t4kJnDfCzNOrkXcDACCqtyM= github.com/openimsdk/gomake v0.0.15-alpha.2 h1:5Q8yl8ezy2yx+q8/ucU/t4kJnDfCzNOrkXcDACCqtyM=
github.com/openimsdk/gomake v0.0.15-alpha.2/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/gomake v0.0.15-alpha.2/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
github.com/openimsdk/protocol v0.0.72-alpha.66 h1:5KoDY6M4T+pXg449ScF6hqeQ+WenBwNyUJn/t8W0oBQ= github.com/openimsdk/protocol v0.0.72-alpha.68 h1:Ekn6S9Ftt12Xs/p9kJ39RDr2gSwIczz+MmSHQE4lAek=
github.com/openimsdk/protocol v0.0.72-alpha.66/go.mod h1:Iet+piS/jaS+kWWyj6EEr36mk4ISzIRYjoMSVA4dq2M= github.com/openimsdk/protocol v0.0.72-alpha.68/go.mod h1:Iet+piS/jaS+kWWyj6EEr36mk4ISzIRYjoMSVA4dq2M=
github.com/openimsdk/tools v0.0.50-alpha.57 h1:oIKV6vYhqp7TRmZ6Pe+r9RNl1D5s7aB/kE9yQVEWcSY= github.com/openimsdk/tools v0.0.50-alpha.60 h1:dYqYpSdSN5o6CxlEjua2USfwfUiG0tUWFBpqghTjbWE=
github.com/openimsdk/tools v0.0.50-alpha.57/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0= github.com/openimsdk/tools v0.0.50-alpha.60/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=

@ -20,24 +20,26 @@ import (
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
) )
type AuthApi struct{} type AuthApi struct {
Client auth.AuthClient
}
func NewAuthApi() AuthApi { func NewAuthApi(client auth.AuthClient) AuthApi {
return AuthApi{} return AuthApi{client}
} }
func (o *AuthApi) GetAdminToken(c *gin.Context) { func (o *AuthApi) GetAdminToken(c *gin.Context) {
a2r.CallV2(c, auth.GetAdminTokenCaller.Invoke) a2r.Call(c, auth.AuthClient.GetAdminToken, o.Client)
} }
func (o *AuthApi) GetUserToken(c *gin.Context) { func (o *AuthApi) GetUserToken(c *gin.Context) {
a2r.CallV2(c, auth.GetUserTokenCaller.Invoke) a2r.Call(c, auth.AuthClient.GetUserToken, o.Client)
} }
func (o *AuthApi) ParseToken(c *gin.Context) { func (o *AuthApi) ParseToken(c *gin.Context) {
a2r.CallV2(c, auth.ParseTokenCaller.Invoke) a2r.Call(c, auth.AuthClient.ParseToken, o.Client)
} }
func (o *AuthApi) ForceLogout(c *gin.Context) { func (o *AuthApi) ForceLogout(c *gin.Context) {
a2r.CallV2(c, auth.ForceLogoutCaller.Invoke) a2r.Call(c, auth.AuthClient.ForceLogout, o.Client)
} }

@ -20,52 +20,54 @@ import (
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
) )
type ConversationApi struct{} type ConversationApi struct {
Client conversation.ConversationClient
}
func NewConversationApi() ConversationApi { func NewConversationApi(client conversation.ConversationClient) ConversationApi {
return ConversationApi{} return ConversationApi{client}
} }
func (o *ConversationApi) GetAllConversations(c *gin.Context) { func (o *ConversationApi) GetAllConversations(c *gin.Context) {
a2r.CallV2(c, conversation.GetAllConversationsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetAllConversations, o.Client)
} }
func (o *ConversationApi) GetSortedConversationList(c *gin.Context) { func (o *ConversationApi) GetSortedConversationList(c *gin.Context) {
a2r.CallV2(c, conversation.GetSortedConversationListCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetSortedConversationList, o.Client)
} }
func (o *ConversationApi) GetConversation(c *gin.Context) { func (o *ConversationApi) GetConversation(c *gin.Context) {
a2r.CallV2(c, conversation.GetConversationCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetConversation, o.Client)
} }
func (o *ConversationApi) GetConversations(c *gin.Context) { func (o *ConversationApi) GetConversations(c *gin.Context) {
a2r.CallV2(c, conversation.GetConversationsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetConversations, o.Client)
} }
func (o *ConversationApi) SetConversations(c *gin.Context) { func (o *ConversationApi) SetConversations(c *gin.Context) {
a2r.CallV2(c, conversation.SetConversationsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.SetConversations, o.Client)
} }
func (o *ConversationApi) GetConversationOfflinePushUserIDs(c *gin.Context) { func (o *ConversationApi) GetConversationOfflinePushUserIDs(c *gin.Context) {
a2r.CallV2(c, conversation.GetConversationOfflinePushUserIDsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetConversationOfflinePushUserIDs, o.Client)
} }
func (o *ConversationApi) GetFullOwnerConversationIDs(c *gin.Context) { func (o *ConversationApi) GetFullOwnerConversationIDs(c *gin.Context) {
a2r.CallV2(c, conversation.GetFullOwnerConversationIDsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetFullOwnerConversationIDs, o.Client)
} }
func (o *ConversationApi) GetIncrementalConversation(c *gin.Context) { func (o *ConversationApi) GetIncrementalConversation(c *gin.Context) {
a2r.CallV2(c, conversation.GetIncrementalConversationCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetIncrementalConversation, o.Client)
} }
func (o *ConversationApi) GetOwnerConversation(c *gin.Context) { func (o *ConversationApi) GetOwnerConversation(c *gin.Context) {
a2r.CallV2(c, conversation.GetOwnerConversationCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetOwnerConversation, o.Client)
} }
func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) { func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) {
a2r.CallV2(c, conversation.GetNotNotifyConversationIDsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetNotNotifyConversationIDs, o.Client)
} }
func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) { func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
a2r.CallV2(c, conversation.GetPinnedConversationIDsCaller.Invoke) a2r.Call(c, conversation.ConversationClient.GetPinnedConversationIDs, o.Client)
} }

@ -21,94 +21,96 @@ import (
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
) )
type FriendApi struct{} type FriendApi struct {
Client relation.FriendClient
}
func NewFriendApi() FriendApi { func NewFriendApi(client relation.FriendClient) FriendApi {
return FriendApi{} return FriendApi{client}
} }
func (o *FriendApi) ApplyToAddFriend(c *gin.Context) { func (o *FriendApi) ApplyToAddFriend(c *gin.Context) {
a2r.CallV2(c, relation.ApplyToAddFriendCaller.Invoke) a2r.Call(c, relation.FriendClient.ApplyToAddFriend, o.Client)
} }
func (o *FriendApi) RespondFriendApply(c *gin.Context) { func (o *FriendApi) RespondFriendApply(c *gin.Context) {
a2r.CallV2(c, relation.RespondFriendApplyCaller.Invoke) a2r.Call(c, relation.FriendClient.RespondFriendApply, o.Client)
} }
func (o *FriendApi) DeleteFriend(c *gin.Context) { func (o *FriendApi) DeleteFriend(c *gin.Context) {
a2r.CallV2(c, relation.DeleteFriendCaller.Invoke) a2r.Call(c, relation.FriendClient.DeleteFriend, o.Client)
} }
func (o *FriendApi) GetFriendApplyList(c *gin.Context) { func (o *FriendApi) GetFriendApplyList(c *gin.Context) {
a2r.CallV2(c, relation.GetPaginationFriendsApplyToCaller.Invoke) a2r.Call(c, relation.FriendClient.GetPaginationFriendsApplyTo, o.Client)
} }
func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) { func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) {
a2r.CallV2(c, relation.GetDesignatedFriendsApplyCaller.Invoke) a2r.Call(c, relation.FriendClient.GetDesignatedFriendsApply, o.Client)
} }
func (o *FriendApi) GetSelfApplyList(c *gin.Context) { func (o *FriendApi) GetSelfApplyList(c *gin.Context) {
a2r.CallV2(c, relation.GetPaginationFriendsApplyFromCaller.Invoke) a2r.Call(c, relation.FriendClient.GetPaginationFriendsApplyFrom, o.Client)
} }
func (o *FriendApi) GetFriendList(c *gin.Context) { func (o *FriendApi) GetFriendList(c *gin.Context) {
a2r.CallV2(c, relation.GetPaginationFriendsCaller.Invoke) a2r.Call(c, relation.FriendClient.GetPaginationFriends, o.Client)
} }
func (o *FriendApi) GetDesignatedFriends(c *gin.Context) { func (o *FriendApi) GetDesignatedFriends(c *gin.Context) {
a2r.CallV2(c, relation.GetDesignatedFriendsCaller.Invoke) a2r.Call(c, relation.FriendClient.GetDesignatedFriends, o.Client)
} }
func (o *FriendApi) SetFriendRemark(c *gin.Context) { func (o *FriendApi) SetFriendRemark(c *gin.Context) {
a2r.CallV2(c, relation.SetFriendRemarkCaller.Invoke) a2r.Call(c, relation.FriendClient.SetFriendRemark, o.Client)
} }
func (o *FriendApi) AddBlack(c *gin.Context) { func (o *FriendApi) AddBlack(c *gin.Context) {
a2r.CallV2(c, relation.AddBlackCaller.Invoke) a2r.Call(c, relation.FriendClient.AddBlack, o.Client)
} }
func (o *FriendApi) GetPaginationBlacks(c *gin.Context) { func (o *FriendApi) GetPaginationBlacks(c *gin.Context) {
a2r.CallV2(c, relation.GetPaginationBlacksCaller.Invoke) a2r.Call(c, relation.FriendClient.GetPaginationBlacks, o.Client)
} }
func (o *FriendApi) GetSpecifiedBlacks(c *gin.Context) { func (o *FriendApi) GetSpecifiedBlacks(c *gin.Context) {
a2r.CallV2(c, relation.GetSpecifiedBlacksCaller.Invoke) a2r.Call(c, relation.FriendClient.GetSpecifiedBlacks, o.Client)
} }
func (o *FriendApi) RemoveBlack(c *gin.Context) { func (o *FriendApi) RemoveBlack(c *gin.Context) {
a2r.CallV2(c, relation.RemoveBlackCaller.Invoke) a2r.Call(c, relation.FriendClient.RemoveBlack, o.Client)
} }
func (o *FriendApi) ImportFriends(c *gin.Context) { func (o *FriendApi) ImportFriends(c *gin.Context) {
a2r.CallV2(c, relation.ImportFriendsCaller.Invoke) a2r.Call(c, relation.FriendClient.ImportFriends, o.Client)
} }
func (o *FriendApi) IsFriend(c *gin.Context) { func (o *FriendApi) IsFriend(c *gin.Context) {
a2r.CallV2(c, relation.IsFriendCaller.Invoke) a2r.Call(c, relation.FriendClient.IsFriend, o.Client)
} }
func (o *FriendApi) GetFriendIDs(c *gin.Context) { func (o *FriendApi) GetFriendIDs(c *gin.Context) {
a2r.CallV2(c, relation.GetFriendIDsCaller.Invoke) a2r.Call(c, relation.FriendClient.GetFriendIDs, o.Client)
} }
func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) { func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) {
a2r.CallV2(c, relation.GetSpecifiedFriendsInfoCaller.Invoke) a2r.Call(c, relation.FriendClient.GetSpecifiedFriendsInfo, o.Client)
} }
func (o *FriendApi) UpdateFriends(c *gin.Context) { func (o *FriendApi) UpdateFriends(c *gin.Context) {
a2r.CallV2(c, relation.UpdateFriendsCaller.Invoke) a2r.Call(c, relation.FriendClient.UpdateFriends, o.Client)
} }
func (o *FriendApi) GetIncrementalFriends(c *gin.Context) { func (o *FriendApi) GetIncrementalFriends(c *gin.Context) {
a2r.CallV2(c, relation.GetIncrementalFriendsCaller.Invoke) a2r.Call(c, relation.FriendClient.GetIncrementalFriends, o.Client)
} }
// GetIncrementalBlacks is temporarily unused. // GetIncrementalBlacks is temporarily unused.
// Deprecated: This function is currently unused and may be removed in future versions. // Deprecated: This function is currently unused and may be removed in future versions.
func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) { func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) {
a2r.CallV2(c, relation.GetIncrementalBlacksCaller.Invoke) a2r.Call(c, relation.FriendClient.GetIncrementalBlacks, o.Client)
} }
func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) { func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) {
a2r.CallV2(c, relation.GetFullFriendUserIDsCaller.Invoke) a2r.Call(c, relation.FriendClient.GetFullFriendUserIDs, o.Client)
} }

@ -20,146 +20,148 @@ import (
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
) )
type GroupApi struct{} type GroupApi struct {
Client group.GroupClient
}
func NewGroupApi() GroupApi { func NewGroupApi(client group.GroupClient) GroupApi {
return GroupApi{} return GroupApi{client}
} }
func (o *GroupApi) CreateGroup(c *gin.Context) { func (o *GroupApi) CreateGroup(c *gin.Context) {
a2r.CallV2(c, group.CreateGroupCaller.Invoke) a2r.Call(c, group.GroupClient.CreateGroup, o.Client)
} }
func (o *GroupApi) SetGroupInfo(c *gin.Context) { func (o *GroupApi) SetGroupInfo(c *gin.Context) {
a2r.CallV2(c, group.SetGroupInfoCaller.Invoke) a2r.Call(c, group.GroupClient.SetGroupInfo, o.Client)
} }
func (o *GroupApi) SetGroupInfoEx(c *gin.Context) { func (o *GroupApi) SetGroupInfoEx(c *gin.Context) {
a2r.CallV2(c, group.SetGroupInfoExCaller.Invoke) a2r.Call(c, group.GroupClient.SetGroupInfoEx, o.Client)
} }
func (o *GroupApi) JoinGroup(c *gin.Context) { func (o *GroupApi) JoinGroup(c *gin.Context) {
a2r.CallV2(c, group.JoinGroupCaller.Invoke) a2r.Call(c, group.GroupClient.JoinGroup, o.Client)
} }
func (o *GroupApi) QuitGroup(c *gin.Context) { func (o *GroupApi) QuitGroup(c *gin.Context) {
a2r.CallV2(c, group.QuitGroupCaller.Invoke) a2r.Call(c, group.GroupClient.QuitGroup, o.Client)
} }
func (o *GroupApi) ApplicationGroupResponse(c *gin.Context) { func (o *GroupApi) ApplicationGroupResponse(c *gin.Context) {
a2r.CallV2(c, group.GroupApplicationResponseCaller.Invoke) a2r.Call(c, group.GroupClient.GroupApplicationResponse, o.Client)
} }
func (o *GroupApi) TransferGroupOwner(c *gin.Context) { func (o *GroupApi) TransferGroupOwner(c *gin.Context) {
a2r.CallV2(c, group.TransferGroupOwnerCaller.Invoke) a2r.Call(c, group.GroupClient.TransferGroupOwner, o.Client)
} }
func (o *GroupApi) GetRecvGroupApplicationList(c *gin.Context) { func (o *GroupApi) GetRecvGroupApplicationList(c *gin.Context) {
a2r.CallV2(c, group.GetGroupApplicationListCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupApplicationList, o.Client)
} }
func (o *GroupApi) GetUserReqGroupApplicationList(c *gin.Context) { func (o *GroupApi) GetUserReqGroupApplicationList(c *gin.Context) {
a2r.CallV2(c, group.GetUserReqApplicationListCaller.Invoke) a2r.Call(c, group.GroupClient.GetUserReqApplicationList, o.Client)
} }
func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) { func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) {
a2r.CallV2(c, group.GetGroupUsersReqApplicationListCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupUsersReqApplicationList, o.Client)
} }
func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) { func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) {
a2r.CallV2(c, group.GetSpecifiedUserGroupRequestInfoCaller.Invoke) a2r.Call(c, group.GroupClient.GetSpecifiedUserGroupRequestInfo, o.Client)
} }
func (o *GroupApi) GetGroupsInfo(c *gin.Context) { func (o *GroupApi) GetGroupsInfo(c *gin.Context) {
a2r.CallV2(c, group.GetGroupsInfoCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupsInfo, o.Client)
//a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo)) //a2r.Call(c, group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo))
} }
func (o *GroupApi) KickGroupMember(c *gin.Context) { func (o *GroupApi) KickGroupMember(c *gin.Context) {
a2r.CallV2(c, group.KickGroupMemberCaller.Invoke) a2r.Call(c, group.GroupClient.KickGroupMember, o.Client)
} }
func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) { func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) {
a2r.CallV2(c, group.GetGroupMembersInfoCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupMembersInfo, o.Client)
//a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo)) //a2r.Call(c, group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo))
} }
func (o *GroupApi) GetGroupMemberList(c *gin.Context) { func (o *GroupApi) GetGroupMemberList(c *gin.Context) {
a2r.CallV2(c, group.GetGroupMemberListCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupMemberList, o.Client)
} }
func (o *GroupApi) InviteUserToGroup(c *gin.Context) { func (o *GroupApi) InviteUserToGroup(c *gin.Context) {
a2r.CallV2(c, group.InviteUserToGroupCaller.Invoke) a2r.Call(c, group.GroupClient.InviteUserToGroup, o.Client)
} }
func (o *GroupApi) GetJoinedGroupList(c *gin.Context) { func (o *GroupApi) GetJoinedGroupList(c *gin.Context) {
a2r.CallV2(c, group.GetJoinedGroupListCaller.Invoke) a2r.Call(c, group.GroupClient.GetJoinedGroupList, o.Client)
} }
func (o *GroupApi) DismissGroup(c *gin.Context) { func (o *GroupApi) DismissGroup(c *gin.Context) {
a2r.CallV2(c, group.DismissGroupCaller.Invoke) a2r.Call(c, group.GroupClient.DismissGroup, o.Client)
} }
func (o *GroupApi) MuteGroupMember(c *gin.Context) { func (o *GroupApi) MuteGroupMember(c *gin.Context) {
a2r.CallV2(c, group.MuteGroupMemberCaller.Invoke) a2r.Call(c, group.GroupClient.MuteGroupMember, o.Client)
} }
func (o *GroupApi) CancelMuteGroupMember(c *gin.Context) { func (o *GroupApi) CancelMuteGroupMember(c *gin.Context) {
a2r.CallV2(c, group.CancelMuteGroupMemberCaller.Invoke) a2r.Call(c, group.GroupClient.CancelMuteGroupMember, o.Client)
} }
func (o *GroupApi) MuteGroup(c *gin.Context) { func (o *GroupApi) MuteGroup(c *gin.Context) {
a2r.CallV2(c, group.MuteGroupCaller.Invoke) a2r.Call(c, group.GroupClient.MuteGroup, o.Client)
} }
func (o *GroupApi) CancelMuteGroup(c *gin.Context) { func (o *GroupApi) CancelMuteGroup(c *gin.Context) {
a2r.CallV2(c, group.CancelMuteGroupCaller.Invoke) a2r.Call(c, group.GroupClient.CancelMuteGroup, o.Client)
} }
func (o *GroupApi) SetGroupMemberInfo(c *gin.Context) { func (o *GroupApi) SetGroupMemberInfo(c *gin.Context) {
a2r.CallV2(c, group.SetGroupMemberInfoCaller.Invoke) a2r.Call(c, group.GroupClient.SetGroupMemberInfo, o.Client)
} }
func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) { func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) {
a2r.CallV2(c, group.GetGroupAbstractInfoCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupAbstractInfo, o.Client)
} }
// func (g *Group) SetGroupMemberNickname(c *gin.Context) { // func (g *Group) SetGroupMemberNickname(c *gin.Context) {
// a2r.Call(group.GroupClient.SetGroupMemberNickname, g.userClient, c) // a2r.Call(c, group.GroupClient.SetGroupMemberNickname, g.userClient)
//} //}
// //
// func (g *Group) GetGroupAllMemberList(c *gin.Context) { // func (g *Group) GetGroupAllMemberList(c *gin.Context) {
// a2r.Call(group.GroupClient.GetGroupAllMember, g.userClient, c) // a2r.Call(c, group.GroupClient.GetGroupAllMember, g.userClient)
//} //}
func (o *GroupApi) GroupCreateCount(c *gin.Context) { func (o *GroupApi) GroupCreateCount(c *gin.Context) {
a2r.CallV2(c, group.GroupCreateCountCaller.Invoke) a2r.Call(c, group.GroupClient.GroupCreateCount, o.Client)
} }
func (o *GroupApi) GetGroups(c *gin.Context) { func (o *GroupApi) GetGroups(c *gin.Context) {
a2r.CallV2(c, group.GetGroupsCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroups, o.Client)
} }
func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) { func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) {
a2r.CallV2(c, group.GetGroupMemberUserIDsCaller.Invoke) a2r.Call(c, group.GroupClient.GetGroupMemberUserIDs, o.Client)
} }
func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) { func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) {
a2r.CallV2(c, group.GetIncrementalJoinGroupCaller.Invoke) a2r.Call(c, group.GroupClient.GetIncrementalJoinGroup, o.Client)
} }
func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) { func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) {
a2r.CallV2(c, group.GetIncrementalGroupMemberCaller.Invoke) a2r.Call(c, group.GroupClient.GetIncrementalGroupMember, o.Client)
} }
func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) { func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) {
a2r.CallV2(c, group.BatchGetIncrementalGroupMemberCaller.Invoke) a2r.Call(c, group.GroupClient.BatchGetIncrementalGroupMember, o.Client)
} }
func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) { func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) {
a2r.CallV2(c, group.GetFullGroupMemberUserIDsCaller.Invoke) a2r.Call(c, group.GroupClient.GetFullGroupMemberUserIDs, o.Client)
} }
func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) { func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) {
a2r.CallV2(c, group.GetFullJoinGroupIDsCaller.Invoke) a2r.Call(c, group.GroupClient.GetFullJoinGroupIDs, o.Client)
} }

@ -30,7 +30,6 @@ import (
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd" disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
@ -40,7 +39,6 @@ import (
"github.com/openimsdk/tools/utils/jsonutil" "github.com/openimsdk/tools/utils/jsonutil"
"github.com/openimsdk/tools/utils/network" "github.com/openimsdk/tools/utils/network"
"github.com/openimsdk/tools/utils/runtimeenv" "github.com/openimsdk/tools/utils/runtimeenv"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
) )
@ -65,9 +63,6 @@ func Start(ctx context.Context, index int, config *Config) error {
return errs.WrapMsg(err, "failed to register discovery service") return errs.WrapMsg(err, "failed to register discovery service")
} }
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
if err = rpcclient.InitRpcCaller(client, config.Discovery.RpcService); err != nil {
return err
}
var ( var (
netDone = make(chan struct{}, 1) netDone = make(chan struct{}, 1)
@ -95,11 +90,10 @@ func Start(ctx context.Context, index int, config *Config) error {
return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap() return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
} }
var etcdClient *clientv3.Client router, err := newGinRouter(ctx, client, config)
if config.Discovery.Enable == conf.ETCD { if err != nil {
etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient() return err
} }
router := newGinRouter(client, config, etcdClient)
if config.API.Prometheus.Enable { if config.API.Prometheus.Enable {
var ( var (
listener net.Listener listener net.Listener
@ -111,6 +105,8 @@ func Start(ctx context.Context, index int, config *Config) error {
return err return err
} }
etcdClient := client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
_, err = etcdClient.Put(ctx, prommetrics.BuildDiscoveryKey(prommetrics.APIKeyName), jsonutil.StructToJsonString(prommetrics.BuildDefaultTarget(registerIP, prometheusPort))) _, err = etcdClient.Put(ctx, prommetrics.BuildDiscoveryKey(prommetrics.APIKeyName), jsonutil.StructToJsonString(prommetrics.BuildDefaultTarget(registerIP, prometheusPort)))
if err != nil { if err != nil {
return errs.WrapMsg(err, "etcd put err") return errs.WrapMsg(err, "etcd put err")

@ -2,16 +2,15 @@ package jssdk
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"sort" "sort"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/jssdk" "github.com/openimsdk/protocol/jssdk"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/mcontext"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
) )
@ -26,6 +25,11 @@ func NewJSSdkApi() *JSSdk {
} }
type JSSdk struct { type JSSdk struct {
userClient rpcli.UserClient
relationClient rpcli.RelationClient
groupClient rpcli.GroupClient
conversationClient rpcli.ConversationClient
msgClient rpcli.MsgClient
} }
func (x *JSSdk) GetActiveConversations(c *gin.Context) { func (x *JSSdk) GetActiveConversations(c *gin.Context) {
@ -57,11 +61,11 @@ func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.Co
groupMap map[string]*sdkws.GroupInfo groupMap map[string]*sdkws.GroupInfo
) )
if len(userIDs) > 0 { if len(userIDs) > 0 {
users, err := field(ctx, user.GetDesignateUsersCaller.Invoke, &user.GetDesignateUsersReq{UserIDs: userIDs}, (*user.GetDesignateUsersResp).GetUsersInfo) users, err := x.userClient.GetUsersInfo(ctx, userIDs)
if err != nil { if err != nil {
return err return err
} }
friends, err := field(ctx, relation.GetFriendInfoCaller.Invoke, &relation.GetFriendInfoReq{OwnerUserID: conversations[0].Conversation.OwnerUserID, FriendUserIDs: userIDs}, (*relation.GetFriendInfoResp).GetFriendInfos) friends, err := x.relationClient.GetFriendsInfo(ctx, conversations[0].Conversation.OwnerUserID, userIDs)
if err != nil { if err != nil {
return err return err
} }
@ -69,11 +73,11 @@ func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.Co
friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID) friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID)
} }
if len(groupIDs) > 0 { if len(groupIDs) > 0 {
resp, err := group.GetGroupsInfoCaller.Invoke(ctx, &group.GetGroupsInfoReq{GroupIDs: groupIDs}) groups, err := x.groupClient.GetGroupsInfo(ctx, groupIDs)
if err != nil { if err != nil {
return err return err
} }
groupMap = datautil.SliceToMap(resp.GroupInfos, (*sdkws.GroupInfo).GetGroupID) groupMap = datautil.SliceToMap(groups, (*sdkws.GroupInfo).GetGroupID)
} }
for _, c := range conversations { for _, c := range conversations {
if c.Conversation.GroupID == "" { if c.Conversation.GroupID == "" {
@ -91,21 +95,18 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
req.Count = defaultGetActiveConversation req.Count = defaultGetActiveConversation
} }
req.OwnerUserID = mcontext.GetOpUserID(ctx) req.OwnerUserID = mcontext.GetOpUserID(ctx)
conversationIDs, err := field(ctx, conversation.GetConversationIDsCaller.Invoke, conversationIDs, err := x.conversationClient.GetConversationIDs(ctx, req.OwnerUserID)
&conversation.GetConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(conversationIDs) == 0 { if len(conversationIDs) == 0 {
return &jssdk.GetActiveConversationsResp{}, nil return &jssdk.GetActiveConversationsResp{}, nil
} }
readSeq, err := field(ctx, msg.GetHasReadSeqsCaller.Invoke, readSeq, err := x.msgClient.GetHasReadSeqs(ctx, conversationIDs, req.OwnerUserID)
&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
activeConversation, err := field(ctx, msg.GetActiveConversationCaller.Invoke, activeConversation, err := x.msgClient.GetActiveConversation(ctx, conversationIDs)
&msg.GetActiveConversationReq{ConversationIDs: conversationIDs}, (*msg.GetActiveConversationResp).GetConversations)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -116,8 +117,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
Conversation: activeConversation, Conversation: activeConversation,
} }
if len(activeConversation) > 1 { if len(activeConversation) > 1 {
pinnedConversationIDs, err := field(ctx, conversation.GetPinnedConversationIDsCaller.Invoke, pinnedConversationIDs, err := x.conversationClient.GetPinnedConversationIDs(ctx, req.OwnerUserID)
&conversation.GetPinnedConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -125,25 +125,18 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
} }
sort.Sort(&sortConversations) sort.Sort(&sortConversations)
sortList := sortConversations.Top(int(req.Count)) sortList := sortConversations.Top(int(req.Count))
conversations, err := field(ctx, conversation.GetConversationsCaller.Invoke, conversations, err := x.conversationClient.GetConversations(ctx, datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
&conversation.GetConversationsReq{ return c.ConversationID
OwnerUserID: req.OwnerUserID, }), req.OwnerUserID)
ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
return c.ConversationID
})}, (*conversation.GetConversationsResp).GetConversations)
if err != nil { if err != nil {
return nil, err return nil, err
} }
msgs, err := field(ctx, msg.GetSeqMessageCaller.Invoke, msgs, err := x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
&msg.GetSeqMessageReq{ return &msg.ConversationSeqs{
UserID: req.OwnerUserID, ConversationID: c.ConversationID,
Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs { Seqs: []int64{c.MaxSeq},
return &msg.ConversationSeqs{ }
ConversationID: c.ConversationID, }))
Seqs: []int64{c.MaxSeq},
}
}),
}, (*msg.GetSeqMessageResp).GetMsgs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -185,7 +178,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) { func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) {
req.OwnerUserID = mcontext.GetOpUserID(ctx) req.OwnerUserID = mcontext.GetOpUserID(ctx)
conversations, err := field(ctx, conversation.GetConversationsCaller.Invoke, &conversation.GetConversationsReq{OwnerUserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*conversation.GetConversationsResp).GetConversations) conversations, err := x.conversationClient.GetConversations(ctx, req.ConversationIDs, req.OwnerUserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,13 +188,11 @@ func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversation
req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string { req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
return c.ConversationID return c.ConversationID
}) })
maxSeqs, err := field(ctx, msg.GetMaxSeqsCaller.Invoke, maxSeqs, err := x.msgClient.GetMaxSeqs(ctx, req.ConversationIDs)
&msg.GetMaxSeqsReq{ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
readSeqs, err := field(ctx, msg.GetHasReadSeqsCaller.Invoke, readSeqs, err := x.msgClient.GetHasReadSeqs(ctx, req.ConversationIDs, req.OwnerUserID)
&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -216,8 +207,7 @@ func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversation
} }
var msgs map[string]*sdkws.PullMsgs var msgs map[string]*sdkws.PullMsgs
if len(conversationSeqs) > 0 { if len(conversationSeqs) > 0 {
msgs, err = field(ctx, msg.GetSeqMessageCaller.Invoke, msgs, err = x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, conversationSeqs)
&msg.GetSeqMessageReq{UserID: req.OwnerUserID, Conversations: conversationSeqs}, (*msg.GetSeqMessageResp).GetMsgs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -21,11 +21,10 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
"github.com/openimsdk/tools/apiresp" "github.com/openimsdk/tools/apiresp"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
@ -38,12 +37,14 @@ import (
) )
type MessageApi struct { type MessageApi struct {
validate *validator.Validate Client msg.MsgClient
userClient *rpcli.UserClient
imAdminUserID []string imAdminUserID []string
validate *validator.Validate
} }
func NewMessageApi(imAdminUserID []string) MessageApi { func NewMessageApi(client msg.MsgClient, userClient *rpcli.UserClient, imAdminUserID []string) MessageApi {
return MessageApi{validate: validator.New(), imAdminUserID: imAdminUserID} return MessageApi{Client: client, userClient: userClient, imAdminUserID: imAdminUserID, validate: validator.New()}
} }
func (*MessageApi) SetOptions(options map[string]bool, value bool) { func (*MessageApi) SetOptions(options map[string]bool, value bool) {
@ -105,51 +106,51 @@ func (m *MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg
} }
func (m *MessageApi) GetSeq(c *gin.Context) { func (m *MessageApi) GetSeq(c *gin.Context) {
a2r.CallV2(c, msg.GetMaxSeqCaller.Invoke) a2r.Call(c, msg.MsgClient.GetMaxSeq, m.Client)
} }
func (m *MessageApi) PullMsgBySeqs(c *gin.Context) { func (m *MessageApi) PullMsgBySeqs(c *gin.Context) {
a2r.CallV2(c, msg.PullMessageBySeqsCaller.Invoke) a2r.Call(c, msg.MsgClient.PullMessageBySeqs, m.Client)
} }
func (m *MessageApi) RevokeMsg(c *gin.Context) { func (m *MessageApi) RevokeMsg(c *gin.Context) {
a2r.CallV2(c, msg.RevokeMsgCaller.Invoke) a2r.Call(c, msg.MsgClient.RevokeMsg, m.Client)
} }
func (m *MessageApi) MarkMsgsAsRead(c *gin.Context) { func (m *MessageApi) MarkMsgsAsRead(c *gin.Context) {
a2r.CallV2(c, msg.MarkMsgsAsReadCaller.Invoke) a2r.Call(c, msg.MsgClient.MarkMsgsAsRead, m.Client)
} }
func (m *MessageApi) MarkConversationAsRead(c *gin.Context) { func (m *MessageApi) MarkConversationAsRead(c *gin.Context) {
a2r.CallV2(c, msg.MarkConversationAsReadCaller.Invoke) a2r.Call(c, msg.MsgClient.MarkConversationAsRead, m.Client)
} }
func (m *MessageApi) GetConversationsHasReadAndMaxSeq(c *gin.Context) { func (m *MessageApi) GetConversationsHasReadAndMaxSeq(c *gin.Context) {
a2r.CallV2(c, msg.GetConversationsHasReadAndMaxSeqCaller.Invoke) a2r.Call(c, msg.MsgClient.GetConversationsHasReadAndMaxSeq, m.Client)
} }
func (m *MessageApi) SetConversationHasReadSeq(c *gin.Context) { func (m *MessageApi) SetConversationHasReadSeq(c *gin.Context) {
a2r.CallV2(c, msg.SetConversationHasReadSeqCaller.Invoke) a2r.Call(c, msg.MsgClient.SetConversationHasReadSeq, m.Client)
} }
func (m *MessageApi) ClearConversationsMsg(c *gin.Context) { func (m *MessageApi) ClearConversationsMsg(c *gin.Context) {
a2r.CallV2(c, msg.ClearConversationsMsgCaller.Invoke) a2r.Call(c, msg.MsgClient.ClearConversationsMsg, m.Client)
} }
func (m *MessageApi) UserClearAllMsg(c *gin.Context) { func (m *MessageApi) UserClearAllMsg(c *gin.Context) {
a2r.CallV2(c, msg.UserClearAllMsgCaller.Invoke) a2r.Call(c, msg.MsgClient.UserClearAllMsg, m.Client)
} }
func (m *MessageApi) DeleteMsgs(c *gin.Context) { func (m *MessageApi) DeleteMsgs(c *gin.Context) {
a2r.CallV2(c, msg.DeleteMsgsCaller.Invoke) a2r.Call(c, msg.MsgClient.DeleteMsgs, m.Client)
} }
func (m *MessageApi) DeleteMsgPhysicalBySeq(c *gin.Context) { func (m *MessageApi) DeleteMsgPhysicalBySeq(c *gin.Context) {
a2r.CallV2(c, msg.DeleteMsgPhysicalBySeqCaller.Invoke) a2r.Call(c, msg.MsgClient.DeleteMsgPhysicalBySeq, m.Client)
} }
func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) { func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) {
a2r.CallV2(c, msg.DeleteMsgPhysicalCaller.Invoke) a2r.Call(c, msg.MsgClient.DeleteMsgPhysical, m.Client)
} }
func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) { func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) {
@ -170,14 +171,10 @@ func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendM
data = apistruct.AtElem{} data = apistruct.AtElem{}
case constant.Custom: case constant.Custom:
data = apistruct.CustomElem{} data = apistruct.CustomElem{}
case constant.Quote:
data = apistruct.QuoteElem{}
case constant.Stream:
data = apistruct.StreamMsgElem{}
case constant.OANotification: case constant.OANotification:
data = apistruct.OANotificationElem{} data = apistruct.OANotificationElem{}
req.SessionType = constant.NotificationChatType req.SessionType = constant.NotificationChatType
if err = user.GetNotificationAccountCaller.Execute(c, &user.GetNotificationAccountReq{UserID: req.SendID}); err != nil { if err = m.userClient.GetNotificationByID(c, req.SendID); err != nil {
return nil, err return nil, err
} }
default: default:
@ -224,7 +221,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
sendMsgReq.MsgData.RecvID = req.RecvID sendMsgReq.MsgData.RecvID = req.RecvID
// Attempt to send the message using the client. // Attempt to send the message using the client.
respPb, err := msg.SendMsgCaller.Invoke(c, sendMsgReq) respPb, err := m.Client.SendMsg(c, sendMsgReq)
if err != nil { if err != nil {
// Set the status to failed and respond with an error if sending fails. // Set the status to failed and respond with an error if sending fails.
apiresp.GinError(c, err) apiresp.GinError(c, err)
@ -235,7 +232,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
var status = constant.MsgSendSuccessed var status = constant.MsgSendSuccessed
// Attempt to update the message sending status in the system. // Attempt to update the message sending status in the system.
err = msg.SetSendMsgStatusCaller.Execute(c, &msg.SetSendMsgStatusReq{ _, err = m.Client.SetSendMsgStatus(c, &msg.SetSendMsgStatusReq{
Status: int32(status), Status: int32(status),
}) })
@ -287,7 +284,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
}), }),
}, },
} }
respPb, err := msg.SendMsgCaller.Invoke(c, &sendMsgReq) respPb, err := m.Client.SendMsg(c, &sendMsgReq)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -311,13 +308,10 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
var recvIDs []string var recvIDs []string
if req.IsSendAll { if req.IsSendAll {
pageNumber := 1 var pageNumber int32 = 1
showNumber := 500 const showNumber = 500
for { for {
recvIDsPart, err := rpccall.ExtractField(c, user.GetAllUserIDCaller.Invoke, &user.GetAllUserIDReq{Pagination: &sdkws.RequestPagination{ recvIDsPart, err := m.userClient.GetAllUserIDs(c, pageNumber, showNumber)
PageNumber: int32(pageNumber),
ShowNumber: int32(showNumber),
}}, (*user.GetAllUserIDResp).GetUserIDs)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -339,7 +333,7 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
} }
for _, recvID := range recvIDs { for _, recvID := range recvIDs {
sendMsgReq.MsgData.RecvID = recvID sendMsgReq.MsgData.RecvID = recvID
rpcResp, err := msg.SendMsgCaller.Invoke(c, sendMsgReq) rpcResp, err := m.Client.SendMsg(c, sendMsgReq)
if err != nil { if err != nil {
resp.FailedIDs = append(resp.FailedIDs, recvID) resp.FailedIDs = append(resp.FailedIDs, recvID)
continue continue
@ -355,33 +349,33 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
} }
func (m *MessageApi) CheckMsgIsSendSuccess(c *gin.Context) { func (m *MessageApi) CheckMsgIsSendSuccess(c *gin.Context) {
a2r.CallV2(c, msg.GetSendMsgStatusCaller.Invoke) a2r.Call(c, msg.MsgClient.GetSendMsgStatus, m.Client)
} }
func (m *MessageApi) GetUsersOnlineStatus(c *gin.Context) { func (m *MessageApi) GetUsersOnlineStatus(c *gin.Context) {
a2r.CallV2(c, msg.GetSendMsgStatusCaller.Invoke) a2r.Call(c, msg.MsgClient.GetSendMsgStatus, m.Client)
} }
func (m *MessageApi) GetActiveUser(c *gin.Context) { func (m *MessageApi) GetActiveUser(c *gin.Context) {
a2r.CallV2(c, msg.GetActiveUserCaller.Invoke) a2r.Call(c, msg.MsgClient.GetActiveUser, m.Client)
} }
func (m *MessageApi) GetActiveGroup(c *gin.Context) { func (m *MessageApi) GetActiveGroup(c *gin.Context) {
a2r.CallV2(c, msg.GetActiveGroupCaller.Invoke) a2r.Call(c, msg.MsgClient.GetActiveGroup, m.Client)
} }
func (m *MessageApi) SearchMsg(c *gin.Context) { func (m *MessageApi) SearchMsg(c *gin.Context) {
a2r.CallV2(c, msg.SearchMessageCaller.Invoke) a2r.Call(c, msg.MsgClient.SearchMessage, m.Client)
} }
func (m *MessageApi) GetServerTime(c *gin.Context) { func (m *MessageApi) GetServerTime(c *gin.Context) {
a2r.CallV2(c, msg.GetServerTimeCaller.Invoke) a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
} }
func (m *MessageApi) GetStreamMsg(c *gin.Context) { func (m *MessageApi) GetStreamMsg(c *gin.Context) {
a2r.CallV2(c, msg.GetStreamMsgCaller.Invoke) a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
} }
func (m *MessageApi) AppendStreamMsg(c *gin.Context) { func (m *MessageApi) AppendStreamMsg(c *gin.Context) {
a2r.CallV2(c, msg.AppendStreamMsgCaller.Invoke) a2r.Call(c, msg.MsgClient.GetServerTime, m.Client)
} }

@ -1,29 +1,36 @@
package api package api
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"github.com/openimsdk/open-im-server/v3/internal/api/jssdk"
pbAuth "github.com/openimsdk/protocol/auth"
clientv3 "go.etcd.io/etcd/client/v3"
"github.com/gin-contrib/gzip" "github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"google.golang.org/grpc" "github.com/openimsdk/open-im-server/v3/internal/api/jssdk"
"google.golang.org/grpc/credentials/insecure" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
pbAuth "github.com/openimsdk/protocol/auth"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/relation"
"github.com/openimsdk/protocol/third"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/apiresp" "github.com/openimsdk/tools/apiresp"
"github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mw" "github.com/openimsdk/tools/mw"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
) )
const ( const (
@ -48,15 +55,43 @@ func prommetricsGin() gin.HandlerFunc {
} }
} }
func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client *clientv3.Client) *gin.Engine { func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cfg *Config) (*gin.Engine, error) {
disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
authConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Auth)
if err != nil {
return nil, err
}
userConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.User)
if err != nil {
return nil, err
}
groupConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Group)
if err != nil {
return nil, err
}
friendConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Friend)
if err != nil {
return nil, err
}
conversationConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Conversation)
if err != nil {
return nil, err
}
thirdConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Third)
if err != nil {
return nil, err
}
msgConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Msg)
if err != nil {
return nil, err
}
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
r := gin.New() r := gin.New()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok { if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("required_if", RequiredIf) _ = v.RegisterValidation("required_if", RequiredIf)
} }
switch config.API.Api.CompressionLevel { switch cfg.API.Api.CompressionLevel {
case NoCompression: case NoCompression:
case DefaultCompression: case DefaultCompression:
r.Use(gzip.Gzip(gzip.DefaultCompression)) r.Use(gzip.Gzip(gzip.DefaultCompression))
@ -65,13 +100,12 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
case BestSpeed: case BestSpeed:
r.Use(gzip.Gzip(gzip.BestSpeed)) r.Use(gzip.Gzip(gzip.BestSpeed))
} }
r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken()) r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)))
u := NewUserApi(disCov, config.Discovery.RpcService.MessageGateway)
m := NewMessageApi(config.Share.IMAdminUserID)
j := jssdk.NewJSSdkApi() j := jssdk.NewJSSdkApi()
userRouterGroup := r.Group("/user") u := NewUserApi(user.NewUserClient(userConn), client, cfg.Discovery.RpcService)
{ {
userRouterGroup := r.Group("/user")
userRouterGroup.POST("/user_register", u.UserRegister) userRouterGroup.POST("/user_register", u.UserRegister)
userRouterGroup.POST("/update_user_info", u.UpdateUserInfo) userRouterGroup.POST("/update_user_info", u.UpdateUserInfo)
userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx) userRouterGroup.POST("/update_user_info_ex", u.UpdateUserInfoEx)
@ -97,9 +131,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount) userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount)
} }
// friend routing group // friend routing group
friendRouterGroup := r.Group("/friend")
{ {
f := NewFriendApi() f := NewFriendApi(relation.NewFriendClient(friendConn))
friendRouterGroup := r.Group("/friend")
friendRouterGroup.POST("/delete_friend", f.DeleteFriend) friendRouterGroup.POST("/delete_friend", f.DeleteFriend)
friendRouterGroup.POST("/get_friend_apply_list", f.GetFriendApplyList) friendRouterGroup.POST("/get_friend_apply_list", f.GetFriendApplyList)
friendRouterGroup.POST("/get_designated_friend_apply", f.GetDesignatedFriendsApply) friendRouterGroup.POST("/get_designated_friend_apply", f.GetDesignatedFriendsApply)
@ -122,9 +156,10 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends) friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends)
friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs) friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs)
} }
g := NewGroupApi()
groupRouterGroup := r.Group("/group") g := NewGroupApi(group.NewGroupClient(groupConn))
{ {
groupRouterGroup := r.Group("/group")
groupRouterGroup.POST("/create_group", g.CreateGroup) groupRouterGroup.POST("/create_group", g.CreateGroup)
groupRouterGroup.POST("/set_group_info", g.SetGroupInfo) groupRouterGroup.POST("/set_group_info", g.SetGroupInfo)
groupRouterGroup.POST("/set_group_info_ex", g.SetGroupInfoEx) groupRouterGroup.POST("/set_group_info_ex", g.SetGroupInfoEx)
@ -158,18 +193,19 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
groupRouterGroup.POST("/get_full_join_group_ids", g.GetFullJoinGroupIDs) groupRouterGroup.POST("/get_full_join_group_ids", g.GetFullJoinGroupIDs)
} }
// certificate // certificate
authRouterGroup := r.Group("/auth")
{ {
a := NewAuthApi() a := NewAuthApi(pbAuth.NewAuthClient(authConn))
authRouterGroup := r.Group("/auth")
authRouterGroup.POST("/get_admin_token", a.GetAdminToken) authRouterGroup.POST("/get_admin_token", a.GetAdminToken)
authRouterGroup.POST("/get_user_token", a.GetUserToken) authRouterGroup.POST("/get_user_token", a.GetUserToken)
authRouterGroup.POST("/parse_token", a.ParseToken) authRouterGroup.POST("/parse_token", a.ParseToken)
authRouterGroup.POST("/force_logout", a.ForceLogout) authRouterGroup.POST("/force_logout", a.ForceLogout)
} }
// Third service // Third service
thirdGroup := r.Group("/third")
{ {
t := NewThirdApi(config.API.Prometheus.GrafanaURL) t := NewThirdApi(third.NewThirdClient(thirdConn), cfg.API.Prometheus.GrafanaURL)
thirdGroup := r.Group("/third")
thirdGroup.GET("/prometheus", t.GetPrometheus) thirdGroup.GET("/prometheus", t.GetPrometheus)
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken) thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
thirdGroup.POST("/set_app_badge", t.SetAppBadge) thirdGroup.POST("/set_app_badge", t.SetAppBadge)
@ -192,8 +228,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
objectGroup.GET("/*name", t.ObjectRedirect) objectGroup.GET("/*name", t.ObjectRedirect)
} }
// Message // Message
msgGroup := r.Group("/msg") m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), cfg.Share.IMAdminUserID)
{ {
msgGroup := r.Group("/msg")
msgGroup.POST("/newest_seq", m.GetSeq) msgGroup.POST("/newest_seq", m.GetSeq)
msgGroup.POST("/search_msg", m.SearchMsg) msgGroup.POST("/search_msg", m.SearchMsg)
msgGroup.POST("/send_msg", m.SendMessage) msgGroup.POST("/send_msg", m.SendMessage)
@ -218,9 +255,9 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
msgGroup.POST("/append_stream_msg", m.AppendStreamMsg) msgGroup.POST("/append_stream_msg", m.AppendStreamMsg)
} }
// Conversation // Conversation
conversationGroup := r.Group("/conversation")
{ {
c := NewConversationApi() c := NewConversationApi(conversation.NewConversationClient(conversationConn))
conversationGroup := r.Group("/conversation")
conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList) conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList)
conversationGroup.POST("/get_all_conversations", c.GetAllConversations) conversationGroup.POST("/get_all_conversations", c.GetAllConversations)
conversationGroup.POST("/get_conversation", c.GetConversation) conversationGroup.POST("/get_conversation", c.GetConversation)
@ -234,42 +271,51 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs) conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
} }
statisticsGroup := r.Group("/statistics")
{ {
statisticsGroup := r.Group("/statistics")
statisticsGroup.POST("/user/register", u.UserRegisterCount) statisticsGroup.POST("/user/register", u.UserRegisterCount)
statisticsGroup.POST("/user/active", m.GetActiveUser) statisticsGroup.POST("/user/active", m.GetActiveUser)
statisticsGroup.POST("/group/create", g.GroupCreateCount) statisticsGroup.POST("/group/create", g.GroupCreateCount)
statisticsGroup.POST("/group/active", m.GetActiveGroup) statisticsGroup.POST("/group/active", m.GetActiveGroup)
} }
jssdk := r.Group("/jssdk") {
jssdk.POST("/get_conversations", j.GetConversations) jssdk := r.Group("/jssdk")
jssdk.POST("/get_active_conversations", j.GetActiveConversations) jssdk.POST("/get_conversations", j.GetConversations)
jssdk.POST("/get_active_conversations", j.GetActiveConversations)
pd := NewPrometheusDiscoveryApi(config, disCov) }
proDiscoveryGroup := r.Group("/prometheus_discovery", pd.Enable) {
proDiscoveryGroup.GET("/api", pd.Api) pd := NewPrometheusDiscoveryApi(cfg, client)
proDiscoveryGroup.GET("/user", pd.User) proDiscoveryGroup := r.Group("/prometheus_discovery", pd.Enable)
proDiscoveryGroup.GET("/group", pd.Group) proDiscoveryGroup.GET("/api", pd.Api)
proDiscoveryGroup.GET("/msg", pd.Msg) proDiscoveryGroup.GET("/user", pd.User)
proDiscoveryGroup.GET("/friend", pd.Friend) proDiscoveryGroup.GET("/group", pd.Group)
proDiscoveryGroup.GET("/conversation", pd.Conversation) proDiscoveryGroup.GET("/msg", pd.Msg)
proDiscoveryGroup.GET("/third", pd.Third) proDiscoveryGroup.GET("/friend", pd.Friend)
proDiscoveryGroup.GET("/auth", pd.Auth) proDiscoveryGroup.GET("/conversation", pd.Conversation)
proDiscoveryGroup.GET("/push", pd.Push) proDiscoveryGroup.GET("/third", pd.Third)
proDiscoveryGroup.GET("/msg_gateway", pd.MessageGateway) proDiscoveryGroup.GET("/auth", pd.Auth)
proDiscoveryGroup.GET("/msg_transfer", pd.MessageTransfer) proDiscoveryGroup.GET("/push", pd.Push)
proDiscoveryGroup.GET("/msg_gateway", pd.MessageGateway)
proDiscoveryGroup.GET("/msg_transfer", pd.MessageTransfer)
}
cm := NewConfigManager(config.Share.IMAdminUserID, config.AllConfig, client, config.ConfigPath, config.RuntimeEnv) {
configGroup := r.Group("/config", cm.CheckAdmin) var etcdClient *clientv3.Client
configGroup.POST("/get_config_list", cm.GetConfigList) if cfg.Discovery.Enable == config.ETCD {
configGroup.POST("/get_config", cm.GetConfig) etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
configGroup.POST("/set_config", cm.SetConfig) }
configGroup.POST("/reset_config", cm.ResetConfig) cm := NewConfigManager(cfg.Share.IMAdminUserID, cfg.AllConfig, etcdClient, cfg.ConfigPath, cfg.RuntimeEnv)
return r configGroup := r.Group("/config", cm.CheckAdmin)
configGroup.POST("/get_config_list", cm.GetConfigList)
configGroup.POST("/get_config", cm.GetConfig)
configGroup.POST("/set_config", cm.SetConfig)
configGroup.POST("/reset_config", cm.ResetConfig)
}
return r, nil
} }
func GinParseToken() gin.HandlerFunc { func GinParseToken(authClient *rpcli.AuthClient) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
switch c.Request.Method { switch c.Request.Method {
case http.MethodPost: case http.MethodPost:
@ -287,7 +333,7 @@ func GinParseToken() gin.HandlerFunc {
c.Abort() c.Abort()
return return
} }
resp, err := pbAuth.ParseTokenCaller.Invoke(c, &pbAuth.ParseTokenReq{Token: token}) resp, err := authClient.ParseToken(c, token)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
c.Abort() c.Abort()

@ -1,31 +0,0 @@
// 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 api
import (
"github.com/gin-gonic/gin"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/a2r"
)
type StatisticsApi struct{}
func NewStatisticsApi() StatisticsApi {
return StatisticsApi{}
}
func (s *StatisticsApi) UserRegister(c *gin.Context) {
a2r.CallV2(c, user.UserRegisterCountCaller.Invoke)
}

@ -16,14 +16,13 @@ package api
import ( import (
"context" "context"
"google.golang.org/grpc"
"math/rand" "math/rand"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"google.golang.org/grpc"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/protocol/third" "github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/a2r" "github.com/openimsdk/tools/a2r"
@ -33,18 +32,19 @@ import (
type ThirdApi struct { type ThirdApi struct {
GrafanaUrl string GrafanaUrl string
Client third.ThirdClient
} }
func NewThirdApi(grafanaUrl string) ThirdApi { func NewThirdApi(client third.ThirdClient, grafanaUrl string) ThirdApi {
return ThirdApi{GrafanaUrl: grafanaUrl} return ThirdApi{Client: client, GrafanaUrl: grafanaUrl}
} }
func (o *ThirdApi) FcmUpdateToken(c *gin.Context) { func (o *ThirdApi) FcmUpdateToken(c *gin.Context) {
a2r.CallV2(c, third.FcmUpdateTokenCaller.Invoke) a2r.Call(c, third.ThirdClient.FcmUpdateToken, o.Client)
} }
func (o *ThirdApi) SetAppBadge(c *gin.Context) { func (o *ThirdApi) SetAppBadge(c *gin.Context) {
a2r.CallV2(c, third.SetAppBadgeCaller.Invoke) a2r.Call(c, third.ThirdClient.SetAppBadge, o.Client)
} }
// #################### s3 #################### // #################### s3 ####################
@ -79,44 +79,44 @@ func setURLPrefix(c *gin.Context, urlPrefix *string) error {
} }
func (o *ThirdApi) PartLimit(c *gin.Context) { func (o *ThirdApi) PartLimit(c *gin.Context) {
a2r.CallV2(c, third.PartLimitCaller.Invoke) a2r.Call(c, third.ThirdClient.PartLimit, o.Client)
} }
func (o *ThirdApi) PartSize(c *gin.Context) { func (o *ThirdApi) PartSize(c *gin.Context) {
a2r.CallV2(c, third.PartSizeCaller.Invoke) a2r.Call(c, third.ThirdClient.PartSize, o.Client)
} }
func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) { func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) {
opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error { opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error {
return setURLPrefix(c, &req.UrlPrefix) return setURLPrefix(c, &req.UrlPrefix)
}) })
a2r.CallV2(c, third.InitiateMultipartUploadCaller.Invoke, opt) a2r.Call(c, third.ThirdClient.InitiateMultipartUpload, o.Client, opt)
} }
func (o *ThirdApi) AuthSign(c *gin.Context) { func (o *ThirdApi) AuthSign(c *gin.Context) {
a2r.CallV2(c, third.AuthSignCaller.Invoke) a2r.Call(c, third.ThirdClient.AuthSign, o.Client)
} }
func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) { func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) {
opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error { opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error {
return setURLPrefix(c, &req.UrlPrefix) return setURLPrefix(c, &req.UrlPrefix)
}) })
a2r.CallV2(c, third.CompleteMultipartUploadCaller.Invoke, opt) a2r.Call(c, third.ThirdClient.CompleteMultipartUpload, o.Client, opt)
} }
func (o *ThirdApi) AccessURL(c *gin.Context) { func (o *ThirdApi) AccessURL(c *gin.Context) {
a2r.CallV2(c, third.AccessURLCaller.Invoke) a2r.Call(c, third.ThirdClient.AccessURL, o.Client)
} }
func (o *ThirdApi) InitiateFormData(c *gin.Context) { func (o *ThirdApi) InitiateFormData(c *gin.Context) {
a2r.CallV2(c, third.InitiateFormDataCaller.Invoke) a2r.Call(c, third.ThirdClient.InitiateFormData, o.Client)
} }
func (o *ThirdApi) CompleteFormData(c *gin.Context) { func (o *ThirdApi) CompleteFormData(c *gin.Context) {
opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error { opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error {
return setURLPrefix(c, &req.UrlPrefix) return setURLPrefix(c, &req.UrlPrefix)
}) })
a2r.CallV2(c, third.CompleteFormDataCaller.Invoke, opt) a2r.Call(c, third.ThirdClient.CompleteFormData, o.Client, opt)
} }
func (o *ThirdApi) ObjectRedirect(c *gin.Context) { func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
@ -140,7 +140,7 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
} }
query[key] = values[0] query[key] = values[0]
} }
resp, err := third.AccessURLCaller.Invoke(ctx, &third.AccessURLReq{Name: name, Query: query}) resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name, Query: query})
if err != nil { if err != nil {
if errs.ErrArgs.Is(err) { if errs.ErrArgs.Is(err) {
c.String(http.StatusBadRequest, err.Error()) c.String(http.StatusBadRequest, err.Error())
@ -158,15 +158,15 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
// #################### logs ####################. // #################### logs ####################.
func (o *ThirdApi) UploadLogs(c *gin.Context) { func (o *ThirdApi) UploadLogs(c *gin.Context) {
a2r.CallV2(c, third.UploadLogsCaller.Invoke) a2r.Call(c, third.ThirdClient.UploadLogs, o.Client)
} }
func (o *ThirdApi) DeleteLogs(c *gin.Context) { func (o *ThirdApi) DeleteLogs(c *gin.Context) {
a2r.CallV2(c, third.DeleteLogsCaller.Invoke) a2r.Call(c, third.ThirdClient.DeleteLogs, o.Client)
} }
func (o *ThirdApi) SearchLogs(c *gin.Context) { func (o *ThirdApi) SearchLogs(c *gin.Context) {
a2r.CallV2(c, third.SearchLogsCaller.Invoke) a2r.Call(c, third.ThirdClient.SearchLogs, o.Client)
} }
func (o *ThirdApi) GetPrometheus(c *gin.Context) { func (o *ThirdApi) GetPrometheus(c *gin.Context) {

@ -16,6 +16,7 @@ package api
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/msggateway" "github.com/openimsdk/protocol/msggateway"
"github.com/openimsdk/protocol/user" "github.com/openimsdk/protocol/user"
@ -27,47 +28,45 @@ import (
) )
type UserApi struct { type UserApi struct {
Discov discovery.SvcDiscoveryRegistry Client user.UserClient
MessageGateWayRpcName string discov discovery.SvcDiscoveryRegistry
config config.RpcService
} }
func NewUserApi(discov discovery.SvcDiscoveryRegistry, messageGateWayRpcName string) UserApi { func NewUserApi(client user.UserClient, discov discovery.SvcDiscoveryRegistry, config config.RpcService) UserApi {
return UserApi{ return UserApi{Client: client, discov: discov, config: config}
Discov: discov,
MessageGateWayRpcName: messageGateWayRpcName,
}
} }
func (u *UserApi) UserRegister(c *gin.Context) { func (u *UserApi) UserRegister(c *gin.Context) {
a2r.CallV2(c, user.UserRegisterCaller.Invoke) a2r.Call(c, user.UserClient.UserRegister, u.Client)
} }
// UpdateUserInfo is deprecated. Use UpdateUserInfoEx // UpdateUserInfo is deprecated. Use UpdateUserInfoEx
func (u *UserApi) UpdateUserInfo(c *gin.Context) { func (u *UserApi) UpdateUserInfo(c *gin.Context) {
a2r.CallV2(c, user.UpdateUserInfoCaller.Invoke) a2r.Call(c, user.UserClient.UpdateUserInfo, u.Client)
} }
func (u *UserApi) UpdateUserInfoEx(c *gin.Context) { func (u *UserApi) UpdateUserInfoEx(c *gin.Context) {
a2r.CallV2(c, user.UpdateUserInfoExCaller.Invoke) a2r.Call(c, user.UserClient.UpdateUserInfoEx, u.Client)
} }
func (u *UserApi) SetGlobalRecvMessageOpt(c *gin.Context) { func (u *UserApi) SetGlobalRecvMessageOpt(c *gin.Context) {
a2r.CallV2(c, user.SetGlobalRecvMessageOptCaller.Invoke) a2r.Call(c, user.UserClient.SetGlobalRecvMessageOpt, u.Client)
} }
func (u *UserApi) GetUsersPublicInfo(c *gin.Context) { func (u *UserApi) GetUsersPublicInfo(c *gin.Context) {
a2r.CallV2(c, user.GetDesignateUsersCaller.Invoke) a2r.Call(c, user.UserClient.GetDesignateUsers, u.Client)
} }
func (u *UserApi) GetAllUsersID(c *gin.Context) { func (u *UserApi) GetAllUsersID(c *gin.Context) {
a2r.CallV2(c, user.GetAllUserIDCaller.Invoke) a2r.Call(c, user.UserClient.GetAllUserID, u.Client)
} }
func (u *UserApi) AccountCheck(c *gin.Context) { func (u *UserApi) AccountCheck(c *gin.Context) {
a2r.CallV2(c, user.AccountCheckCaller.Invoke) a2r.Call(c, user.UserClient.AccountCheck, u.Client)
} }
func (u *UserApi) GetUsers(c *gin.Context) { func (u *UserApi) GetUsers(c *gin.Context) {
a2r.CallV2(c, user.GetPaginationUsersCaller.Invoke) a2r.Call(c, user.UserClient.GetPaginationUsers, u.Client)
} }
// GetUsersOnlineStatus Get user online status. // GetUsersOnlineStatus Get user online status.
@ -77,7 +76,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
} }
conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName) conns, err := u.discov.GetConns(c, u.config.MessageGateway)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -128,7 +127,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
} }
func (u *UserApi) UserRegisterCount(c *gin.Context) { func (u *UserApi) UserRegisterCount(c *gin.Context) {
a2r.CallV2(c, user.UserRegisterCountCaller.Invoke) a2r.Call(c, user.UserClient.UserRegisterCount, u.Client)
} }
// GetUsersOnlineTokenDetail Get user online token details. // GetUsersOnlineTokenDetail Get user online token details.
@ -141,7 +140,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return return
} }
conns, err := u.Discov.GetConns(c, u.MessageGateWayRpcName) conns, err := u.discov.GetConns(c, u.config.MessageGateway)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -194,52 +193,52 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
// SubscriberStatus Presence status of subscribed users. // SubscriberStatus Presence status of subscribed users.
func (u *UserApi) SubscriberStatus(c *gin.Context) { func (u *UserApi) SubscriberStatus(c *gin.Context) {
a2r.CallV2(c, user.SubscribeOrCancelUsersStatusCaller.Invoke) a2r.Call(c, user.UserClient.SubscribeOrCancelUsersStatus, u.Client)
} }
// GetUserStatus Get the online status of the user. // GetUserStatus Get the online status of the user.
func (u *UserApi) GetUserStatus(c *gin.Context) { func (u *UserApi) GetUserStatus(c *gin.Context) {
a2r.CallV2(c, user.GetUserStatusCaller.Invoke) a2r.Call(c, user.UserClient.GetUserStatus, u.Client)
} }
// GetSubscribeUsersStatus Get the online status of subscribers. // GetSubscribeUsersStatus Get the online status of subscribers.
func (u *UserApi) GetSubscribeUsersStatus(c *gin.Context) { func (u *UserApi) GetSubscribeUsersStatus(c *gin.Context) {
a2r.CallV2(c, user.GetSubscribeUsersStatusCaller.Invoke) a2r.Call(c, user.UserClient.GetSubscribeUsersStatus, u.Client)
} }
// ProcessUserCommandAdd user general function add. // ProcessUserCommandAdd user general function add.
func (u *UserApi) ProcessUserCommandAdd(c *gin.Context) { func (u *UserApi) ProcessUserCommandAdd(c *gin.Context) {
a2r.CallV2(c, user.ProcessUserCommandAddCaller.Invoke) a2r.Call(c, user.UserClient.ProcessUserCommandAdd, u.Client)
} }
// ProcessUserCommandDelete user general function delete. // ProcessUserCommandDelete user general function delete.
func (u *UserApi) ProcessUserCommandDelete(c *gin.Context) { func (u *UserApi) ProcessUserCommandDelete(c *gin.Context) {
a2r.CallV2(c, user.ProcessUserCommandDeleteCaller.Invoke) a2r.Call(c, user.UserClient.ProcessUserCommandDelete, u.Client)
} }
// ProcessUserCommandUpdate user general function update. // ProcessUserCommandUpdate user general function update.
func (u *UserApi) ProcessUserCommandUpdate(c *gin.Context) { func (u *UserApi) ProcessUserCommandUpdate(c *gin.Context) {
a2r.CallV2(c, user.ProcessUserCommandUpdateCaller.Invoke) a2r.Call(c, user.UserClient.ProcessUserCommandUpdate, u.Client)
} }
// ProcessUserCommandGet user general function get. // ProcessUserCommandGet user general function get.
func (u *UserApi) ProcessUserCommandGet(c *gin.Context) { func (u *UserApi) ProcessUserCommandGet(c *gin.Context) {
a2r.CallV2(c, user.ProcessUserCommandGetCaller.Invoke) a2r.Call(c, user.UserClient.ProcessUserCommandGet, u.Client)
} }
// ProcessUserCommandGet user general function get all. // ProcessUserCommandGet user general function get all.
func (u *UserApi) ProcessUserCommandGetAll(c *gin.Context) { func (u *UserApi) ProcessUserCommandGetAll(c *gin.Context) {
a2r.CallV2(c, user.ProcessUserCommandGetAllCaller.Invoke) a2r.Call(c, user.UserClient.ProcessUserCommandGetAll, u.Client)
} }
func (u *UserApi) AddNotificationAccount(c *gin.Context) { func (u *UserApi) AddNotificationAccount(c *gin.Context) {
a2r.CallV2(c, user.AddNotificationAccountCaller.Invoke) a2r.Call(c, user.UserClient.AddNotificationAccount, u.Client)
} }
func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) { func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) {
a2r.CallV2(c, user.UpdateNotificationAccountInfoCaller.Invoke) a2r.Call(c, user.UserClient.UpdateNotificationAccountInfo, u.Client)
} }
func (u *UserApi) SearchNotificationAccount(c *gin.Context) { func (u *UserApi) SearchNotificationAccount(c *gin.Context) {
a2r.CallV2(c, user.SearchNotificationAccountCaller.Invoke) a2r.Call(c, user.UserClient.SearchNotificationAccount, u.Client)
} }

@ -16,6 +16,7 @@ package msggateway
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"sync/atomic" "sync/atomic"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
@ -34,7 +35,14 @@ import (
) )
func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error { func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
s.LongConnServer.SetDiscoveryRegistry(disCov, config) userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
s.userClient = rpcli.NewUserClient(userConn)
if err := s.LongConnServer.SetDiscoveryRegistry(ctx, disCov, config); err != nil {
return err
}
msggateway.RegisterMsgGatewayServer(server, s) msggateway.RegisterMsgGatewayServer(server, s)
if s.ready != nil { if s.ready != nil {
return s.ready(s) return s.ready(s)
@ -68,6 +76,7 @@ type Server struct {
pushTerminal map[int]struct{} pushTerminal map[int]struct{}
ready func(srv *Server) error ready func(srv *Server) error
queue *memamq.MemoryQueue queue *memamq.MemoryQueue
userClient *rpcli.UserClient
} }
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {

@ -62,8 +62,9 @@ func Start(ctx context.Context, index int, conf *Config) error {
) )
hubServer := NewServer(longServer, conf, func(srv *Server) error { hubServer := NewServer(longServer, conf, func(srv *Server) error {
longServer.online, _ = rpccache.NewOnlineCache(conf.Share.IMAdminUserID, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges) var err error
return nil longServer.online, err = rpccache.NewOnlineCache(srv.userClient, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges)
return err
}) })
go longServer.ChangeOnlineStatus(4) go longServer.ChangeOnlineStatus(4)

@ -17,6 +17,7 @@ package msggateway
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"sync" "sync"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
@ -99,27 +100,33 @@ func (r *Resp) String() string {
} }
type MessageHandler interface { type MessageHandler interface {
GetSeq(context context.Context, data *Req) ([]byte, error) GetSeq(ctx context.Context, data *Req) ([]byte, error)
SendMessage(context context.Context, data *Req) ([]byte, error) SendMessage(ctx context.Context, data *Req) ([]byte, error)
SendSignalMessage(context context.Context, data *Req) ([]byte, error) SendSignalMessage(ctx context.Context, data *Req) ([]byte, error)
PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error)
GetConversationsHasReadAndMaxSeq(context context.Context, data *Req) ([]byte, error) GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error)
GetSeqMessage(context context.Context, data *Req) ([]byte, error) GetSeqMessage(ctx context.Context, data *Req) ([]byte, error)
UserLogout(context context.Context, data *Req) ([]byte, error) UserLogout(ctx context.Context, data *Req) ([]byte, error)
SetUserDeviceBackground(context context.Context, data *Req) ([]byte, bool, error) SetUserDeviceBackground(ctx context.Context, data *Req) ([]byte, bool, error)
} }
var _ MessageHandler = (*GrpcHandler)(nil) var _ MessageHandler = (*GrpcHandler)(nil)
type GrpcHandler struct { type GrpcHandler struct {
validate *validator.Validate validate *validator.Validate
msgClient *rpcli.MsgClient
pushClient *rpcli.PushMsgServiceClient
} }
func NewGrpcHandler(validate *validator.Validate) *GrpcHandler { func NewGrpcHandler(validate *validator.Validate, msgClient *rpcli.MsgClient, pushClient *rpcli.PushMsgServiceClient) *GrpcHandler {
return &GrpcHandler{validate: validate} return &GrpcHandler{
validate: validate,
msgClient: msgClient,
pushClient: pushClient,
}
} }
func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
req := sdkws.GetMaxSeqReq{} req := sdkws.GetMaxSeqReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq") return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq")
@ -127,7 +134,7 @@ func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
if err := g.validate.Struct(&req); err != nil { if err := g.validate.Struct(&req); err != nil {
return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq") return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq")
} }
resp, err := msg.GetMaxSeqCaller.Invoke(ctx, &req) resp, err := g.msgClient.MsgClient.GetMaxSeq(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -140,7 +147,7 @@ func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
// SendMessage handles the sending of messages through gRPC. It unmarshals the request data, // SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
// validates the message, and then sends it using the message RPC client. // validates the message, and then sends it using the message RPC client.
func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) {
var msgData sdkws.MsgData var msgData sdkws.MsgData
if err := proto.Unmarshal(data.Data, &msgData); err != nil { if err := proto.Unmarshal(data.Data, &msgData); err != nil {
return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData") return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData")
@ -151,7 +158,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
} }
req := msg.SendMsgReq{MsgData: &msgData} req := msg.SendMsgReq{MsgData: &msgData}
resp, err := msg.SendMsgCaller.Invoke(ctx, &req) resp, err := g.msgClient.MsgClient.SendMsg(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -164,8 +171,8 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
return c, nil return c, nil
} }
func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) SendSignalMessage(ctx context.Context, data *Req) ([]byte, error) {
resp, err := msg.SendMsgCaller.Invoke(context, nil) resp, err := g.msgClient.MsgClient.SendMsg(ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -176,7 +183,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
return c, nil return c, nil
} }
func (g GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error) {
req := sdkws.PullMessageBySeqsReq{} req := sdkws.PullMessageBySeqsReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "PullMessageBySeqsReq") return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "PullMessageBySeqsReq")
@ -184,7 +191,7 @@ func (g GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byt
if err := g.validate.Struct(data); err != nil { if err := g.validate.Struct(data); err != nil {
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq") return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq")
} }
resp, err := msg.PullMessageBySeqsCaller.Invoke(ctx, &req) resp, err := g.msgClient.MsgClient.PullMessageBySeqs(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,7 +202,7 @@ func (g GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byt
return c, nil return c, nil
} }
func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error) {
req := msg.GetConversationsHasReadAndMaxSeqReq{} req := msg.GetConversationsHasReadAndMaxSeqReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "GetConversationsHasReadAndMaxSeq") return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "GetConversationsHasReadAndMaxSeq")
@ -203,7 +210,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data
if err := g.validate.Struct(data); err != nil { if err := g.validate.Struct(data); err != nil {
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetConversationsHasReadAndMaxSeq") return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetConversationsHasReadAndMaxSeq")
} }
resp, err := msg.GetConversationsHasReadAndMaxSeqCaller.Invoke(ctx, &req) resp, err := g.msgClient.MsgClient.GetConversationsHasReadAndMaxSeq(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -214,7 +221,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data
return c, nil return c, nil
} }
func (g GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, error) {
req := msg.GetSeqMessageReq{} req := msg.GetSeqMessageReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "GetSeqMessage") return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "GetSeqMessage")
@ -222,7 +229,7 @@ func (g GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, erro
if err := g.validate.Struct(data); err != nil { if err := g.validate.Struct(data); err != nil {
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetSeqMessage") return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetSeqMessage")
} }
resp, err := msg.GetSeqMessageCaller.Invoke(ctx, &req) resp, err := g.msgClient.MsgClient.GetSeqMessage(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -233,12 +240,12 @@ func (g GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, erro
return c, nil return c, nil
} }
func (g GrpcHandler) UserLogout(ctx context.Context, data *Req) ([]byte, error) { func (g *GrpcHandler) UserLogout(ctx context.Context, data *Req) ([]byte, error) {
req := push.DelUserPushTokenReq{} req := push.DelUserPushTokenReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq") return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq")
} }
resp, err := push.DelUserPushTokenCaller.Invoke(ctx, &req) resp, err := g.pushClient.PushMsgServiceClient.DelUserPushToken(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -249,7 +256,7 @@ func (g GrpcHandler) UserLogout(ctx context.Context, data *Req) ([]byte, error)
return c, nil return c, nil
} }
func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) { func (g *GrpcHandler) SetUserDeviceBackground(ctx context.Context, data *Req) ([]byte, bool, error) {
req := sdkws.SetAppBackgroundStatusReq{} req := sdkws.SetAppBackgroundStatusReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { if err := proto.Unmarshal(data.Data, &req); err != nil {
return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq") return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq")

@ -88,7 +88,7 @@ func (ws *WsServer) ChangeOnlineStatus(concurrent int) {
opIdCtx := mcontext.SetOperationID(context.Background(), operationIDPrefix+strconv.FormatInt(count.Add(1), 10)) opIdCtx := mcontext.SetOperationID(context.Background(), operationIDPrefix+strconv.FormatInt(count.Add(1), 10))
ctx, cancel := context.WithTimeout(opIdCtx, time.Second*5) ctx, cancel := context.WithTimeout(opIdCtx, time.Second*5)
defer cancel() defer cancel()
if err := pbuser.SetUserOnlineStatusCaller.Execute(ctx, req); err != nil { if err := ws.userClient.SetUserOnlineStatus(ctx, req); err != nil {
log.ZError(ctx, "update user online status", err) log.ZError(ctx, "update user online status", err)
} }
for _, ss := range req.Status { for _, ss := range req.Status {

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"net/http" "net/http"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -33,7 +34,7 @@ type LongConnServer interface {
GetUserAllCons(userID string) ([]*Client, bool) GetUserAllCons(userID string) ([]*Client, bool)
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
Validate(s any) error Validate(s any) error
SetDiscoveryRegistry(client discovery.SvcDiscoveryRegistry, config *Config) SetDiscoveryRegistry(ctx context.Context, client discovery.SvcDiscoveryRegistry, config *Config) error
KickUserConn(client *Client) error KickUserConn(client *Client) error
UnRegister(c *Client) UnRegister(c *Client)
SetKickHandlerInfo(i *kickHandler) SetKickHandlerInfo(i *kickHandler)
@ -63,6 +64,8 @@ type WsServer struct {
//Encoder //Encoder
MessageHandler MessageHandler
webhookClient *webhook.Client webhookClient *webhook.Client
userClient *rpcli.UserClient
authClient *rpcli.AuthClient
} }
type kickHandler struct { type kickHandler struct {
@ -71,9 +74,28 @@ type kickHandler struct {
newClient *Client newClient *Client
} }
func (ws *WsServer) SetDiscoveryRegistry(disCov discovery.SvcDiscoveryRegistry, config *Config) { func (ws *WsServer) SetDiscoveryRegistry(ctx context.Context, disCov discovery.SvcDiscoveryRegistry, config *Config) error {
ws.MessageHandler = NewGrpcHandler(ws.validate) userConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
pushConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Push)
if err != nil {
return err
}
authConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Auth)
if err != nil {
return err
}
msgConn, err := disCov.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return err
}
ws.userClient = rpcli.NewUserClient(userConn)
ws.authClient = rpcli.NewAuthClient(authConn)
ws.MessageHandler = NewGrpcHandler(ws.validate, rpcli.NewMsgClient(msgConn), rpcli.NewPushMsgServiceClient(pushConn))
ws.disCov = disCov ws.disCov = disCov
return nil
} }
//func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, status int32) { //func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, status int32) {
@ -315,8 +337,7 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(), []string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()}, constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
) )
if err := ws.authClient.KickTokens(ctx, kickTokens); err != nil {
if err := pbAuth.KickTokensCaller.Execute(ctx, &pbAuth.KickTokensReq{Tokens: kickTokens}); err != nil {
log.ZWarn(newClient.ctx, "kickTokens err", err) log.ZWarn(newClient.ctx, "kickTokens err", err)
} }
} }
@ -343,11 +364,12 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(), []string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()}, constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
) )
if err := pbAuth.InvalidateTokenCaller.Execute(ctx, &pbAuth.InvalidateTokenReq{ req := &pbAuth.InvalidateTokenReq{
PreservedToken: newClient.token, PreservedToken: newClient.token,
UserID: newClient.UserID, UserID: newClient.UserID,
PlatformID: int32(newClient.PlatformID), PlatformID: int32(newClient.PlatformID),
}); err != nil { }
if err := ws.authClient.InvalidateToken(ctx, req); err != nil {
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID, log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
"platformID", newClient.PlatformID) "platformID", newClient.PlatformID)
} }
@ -418,7 +440,7 @@ func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) {
} }
// Call the authentication client to parse the Token obtained from the context // Call the authentication client to parse the Token obtained from the context
resp, err := pbAuth.ParseTokenCaller.Invoke(connContext, &pbAuth.ParseTokenReq{Token: connContext.GetToken()}) resp, err := ws.authClient.ParseToken(connContext, connContext.GetToken())
if err != nil { if err != nil {
// If there's an error parsing the Token, decide whether to send the error message via WebSocket based on the context flag // If there's an error parsing the Token, decide whether to send the error message via WebSocket based on the context flag
shouldSendError := connContext.ShouldSendResp() shouldSendError := connContext.ShouldSendResp()

@ -26,7 +26,6 @@ import (
"syscall" "syscall"
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd" disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/utils/jsonutil" "github.com/openimsdk/tools/utils/jsonutil"
@ -94,9 +93,6 @@ func Start(ctx context.Context, index int, config *Config) error {
} }
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
if err = rpcclient.InitRpcCaller(client, config.Discovery.RpcService); err != nil {
return err
}
if config.Discovery.Enable == conf.ETCD { if config.Discovery.Enable == conf.ETCD {
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), []string{ cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), []string{
@ -130,7 +126,7 @@ func Start(ctx context.Context, index int, config *Config) error {
if err != nil { if err != nil {
return err return err
} }
historyCH, err := NewOnlineHistoryRedisConsumerHandler(&config.KafkaConfig, msgTransferDatabase) historyCH, err := NewOnlineHistoryRedisConsumerHandler(ctx, client, config, msgTransferDatabase)
if err != nil { if err != nil {
return err return err
} }

@ -18,6 +18,8 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/tools/discovery"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -25,15 +27,12 @@ import (
"github.com/IBM/sarama" "github.com/IBM/sarama"
"github.com/go-redis/redis" "github.com/go-redis/redis"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/tools/batcher" "github.com/openimsdk/open-im-server/v3/pkg/tools/batcher"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconv "github.com/openimsdk/protocol/conversation" pbconv "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
@ -72,16 +71,30 @@ type OnlineHistoryRedisConsumerHandler struct {
msgTransferDatabase controller.MsgTransferDatabase msgTransferDatabase controller.MsgTransferDatabase
conversationUserHasReadChan chan *userHasReadSeq conversationUserHasReadChan chan *userHasReadSeq
wg sync.WaitGroup wg sync.WaitGroup
groupClient *rpcli.GroupClient
conversationClient *rpcli.ConversationClient
} }
func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.MsgTransferDatabase) (*OnlineHistoryRedisConsumerHandler, error) { func NewOnlineHistoryRedisConsumerHandler(ctx context.Context, client discovery.SvcDiscoveryRegistry, config *Config, database controller.MsgTransferDatabase) (*OnlineHistoryRedisConsumerHandler, error) {
kafkaConf := config.KafkaConfig
historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false) historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return nil, err
}
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
if err != nil {
return nil, err
}
var och OnlineHistoryRedisConsumerHandler var och OnlineHistoryRedisConsumerHandler
och.msgTransferDatabase = database och.msgTransferDatabase = database
och.conversationUserHasReadChan = make(chan *userHasReadSeq, hasReadChanBuffer) och.conversationUserHasReadChan = make(chan *userHasReadSeq, hasReadChanBuffer)
och.groupClient = rpcli.NewGroupClient(groupConn)
och.conversationClient = rpcli.NewConversationClient(conversationConn)
och.wg.Add(1) och.wg.Add(1)
b := batcher.New[sarama.ConsumerMessage]( b := batcher.New[sarama.ConsumerMessage](
@ -109,15 +122,13 @@ func (och *OnlineHistoryRedisConsumerHandler) do(ctx context.Context, channelID
ctx = mcontext.WithTriggerIDContext(ctx, val.TriggerID()) ctx = mcontext.WithTriggerIDContext(ctx, val.TriggerID())
ctxMessages := och.parseConsumerMessages(ctx, val.Val()) ctxMessages := och.parseConsumerMessages(ctx, val.Val())
ctx = withAggregationCtx(ctx, ctxMessages) ctx = withAggregationCtx(ctx, ctxMessages)
log.ZInfo(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMessages), log.ZInfo(ctx, "msg arrived channel", "channel id", channelID, "msgList length", len(ctxMessages), "key", val.Key())
"key", val.Key())
och.doSetReadSeq(ctx, ctxMessages) och.doSetReadSeq(ctx, ctxMessages)
storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList := storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList :=
och.categorizeMessageLists(ctxMessages) och.categorizeMessageLists(ctxMessages)
log.ZDebug(ctx, "number of categorized messages", "storageMsgList", len(storageMsgList), "notStorageMsgList", log.ZDebug(ctx, "number of categorized messages", "storageMsgList", len(storageMsgList), "notStorageMsgList",
len(notStorageMsgList), "storageNotificationList", len(storageNotificationList), "notStorageNotificationList", len(notStorageMsgList), "storageNotificationList", len(storageNotificationList), "notStorageNotificationList", len(notStorageNotificationList))
len(notStorageNotificationList))
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMessages[0].message) conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMessages[0].message)
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMessages[0].message) conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMessages[0].message)
@ -282,31 +293,26 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key
log.ZDebug(ctx, "group chat first create conversation", "conversationID", log.ZDebug(ctx, "group chat first create conversation", "conversationID",
conversationID) conversationID)
userIDs, err := rpccall.ExtractField(ctx, group.GetGroupMemberUserIDsCaller.Invoke, userIDs, err := och.groupClient.GetGroupMemberUserIDs(ctx, msg.GroupID)
&group.GetGroupMemberUserIDsReq{
GroupID: msg.GroupID,
}, (*group.GetGroupMemberUserIDsResp).GetUserIDs)
if err != nil { if err != nil {
log.ZWarn(ctx, "get group member ids error", err, "conversationID", log.ZWarn(ctx, "get group member ids error", err, "conversationID",
conversationID) conversationID)
} else { } else {
log.ZInfo(ctx, "GetGroupMemberIDs end") log.ZInfo(ctx, "GetGroupMemberIDs end")
if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{ if err := och.conversationClient.CreateGroupChatConversations(ctx, msg.GroupID, userIDs); err != nil {
UserIDs: userIDs,
GroupID: msg.GroupID,
}); err != nil {
log.ZWarn(ctx, "single chat first create conversation error", err, log.ZWarn(ctx, "single chat first create conversation error", err,
"conversationID", conversationID) "conversationID", conversationID)
} }
} }
case constant.SingleChatType, constant.NotificationChatType: case constant.SingleChatType, constant.NotificationChatType:
if err := pbconv.CreateSingleChatConversationsCaller.Execute(ctx, &pbconv.CreateSingleChatConversationsReq{ req := &pbconv.CreateSingleChatConversationsReq{
RecvID: msg.RecvID, RecvID: msg.RecvID,
SendID: msg.SendID, SendID: msg.SendID,
ConversationID: conversationID, ConversationID: conversationID,
ConversationType: msg.SessionType, ConversationType: msg.SessionType,
}); err != nil { }
if err := och.conversationClient.CreateSingleChatConversations(ctx, req); err != nil {
log.ZWarn(ctx, "single chat or notification first create conversation error", err, log.ZWarn(ctx, "single chat or notification first create conversation error", err,
"conversationID", conversationID, "sessionType", msg.SessionType) "conversationID", conversationID, "sessionType", msg.SessionType)
} }

@ -37,11 +37,6 @@ type Config struct {
runTimeEnv string runTimeEnv string
} }
func (p pushServer) PushMsg(ctx context.Context, req *pbpush.PushMsgReq) (*pbpush.PushMsgResp, error) {
//todo reserved Interface
return nil, nil
}
func (p pushServer) DelUserPushToken(ctx context.Context, func (p pushServer) DelUserPushToken(ctx context.Context,
req *pbpush.DelUserPushTokenReq) (resp *pbpush.DelUserPushTokenResp, err error) { req *pbpush.DelUserPushTokenReq) (resp *pbpush.DelUserPushTokenResp, err error) {
if err = p.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil { if err = p.database.DelFcmToken(ctx, req.UserID, int(req.PlatformID)); err != nil {
@ -65,7 +60,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
database := controller.NewPushDatabase(cacheModel, &config.KafkaConfig) database := controller.NewPushDatabase(cacheModel, &config.KafkaConfig)
consumer, err := NewConsumerHandler(config, database, offlinePusher, rdb, client) consumer, err := NewConsumerHandler(ctx, config, database, offlinePusher, rdb, client)
if err != nil { if err != nil {
return err return err
} }

@ -3,6 +3,7 @@ package push
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"math/rand" "math/rand"
"strconv" "strconv"
"time" "time"
@ -17,12 +18,8 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpccache"
"github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil" "github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconv "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/msggateway" "github.com/openimsdk/protocol/msggateway"
pbpush "github.com/openimsdk/protocol/push" pbpush "github.com/openimsdk/protocol/push"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
@ -45,9 +42,13 @@ type ConsumerHandler struct {
conversationLocalCache *rpccache.ConversationLocalCache conversationLocalCache *rpccache.ConversationLocalCache
webhookClient *webhook.Client webhookClient *webhook.Client
config *Config config *Config
userClient *rpcli.UserClient
groupClient *rpcli.GroupClient
msgClient *rpcli.MsgClient
conversationClient *rpcli.ConversationClient
} }
func NewConsumerHandler(config *Config, database controller.PushDatabase, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient, func NewConsumerHandler(ctx context.Context, config *Config, database controller.PushDatabase, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient,
client discovery.SvcDiscoveryRegistry) (*ConsumerHandler, error) { client discovery.SvcDiscoveryRegistry) (*ConsumerHandler, error) {
var consumerHandler ConsumerHandler var consumerHandler ConsumerHandler
var err error var err error
@ -56,15 +57,35 @@ func NewConsumerHandler(config *Config, database controller.PushDatabase, offlin
if err != nil { if err != nil {
return nil, err return nil, err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return nil, err
}
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return nil, err
}
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return nil, err
}
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
if err != nil {
return nil, err
}
consumerHandler.userClient = rpcli.NewUserClient(userConn)
consumerHandler.groupClient = rpcli.NewGroupClient(groupConn)
consumerHandler.msgClient = rpcli.NewMsgClient(msgConn)
consumerHandler.conversationClient = rpcli.NewConversationClient(conversationConn)
consumerHandler.offlinePusher = offlinePusher consumerHandler.offlinePusher = offlinePusher
consumerHandler.onlinePusher = NewOnlinePusher(client, config) consumerHandler.onlinePusher = NewOnlinePusher(client, config)
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(&config.LocalCacheConfig, rdb) consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupClient, &config.LocalCacheConfig, rdb)
consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(&config.LocalCacheConfig, rdb) consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationClient, &config.LocalCacheConfig, rdb)
consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL) consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
consumerHandler.config = config consumerHandler.config = config
consumerHandler.pushDatabase = database consumerHandler.pushDatabase = database
consumerHandler.onlineCache, err = rpccache.NewOnlineCache(config.Share.IMAdminUserID, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil) consumerHandler.onlineCache, err = rpccache.NewOnlineCache(consumerHandler.userClient, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -321,7 +342,7 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri
ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0]) ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0])
} }
defer func(groupID string) { defer func(groupID string) {
if err = group.DismissGroupCaller.Execute(ctx, &group.DismissGroupReq{GroupID: groupID}); err != nil { if err := c.groupClient.DismissGroup(ctx, groupID, true); err != nil {
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID) log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
} }
}(groupID) }(groupID)
@ -347,12 +368,7 @@ func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData
func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData, func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData,
offlinePushUserIDs []string) (userIDs []string, err error) { offlinePushUserIDs []string) (userIDs []string, err error) {
needOfflinePushUserIDs, err := c.conversationClient.GetConversationOfflinePushUserIDs(ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs)
//todo local cache Obtain the difference set through local comparison.
needOfflinePushUserIDs, err := rpccall.ExtractField(ctx, pbconv.GetConversationOfflinePushUserIDsCaller.Invoke, &pbconv.GetConversationOfflinePushUserIDsReq{
ConversationID: conversationutil.GenGroupConversationID(groupID),
UserIDs: offlinePushUserIDs,
}, (*pbconv.GetConversationOfflinePushUserIDsResp).GetUserIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -406,18 +422,11 @@ func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, conten
func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error { func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke, maxSeq, err := c.msgClient.GetConversationMaxSeq(ctx, conversationID)
&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
(*msg.GetConversationMaxSeqResp).GetMaxSeq)
if err != nil { if err != nil {
return err return err
} }
return c.conversationClient.SetConversationMaxSeq(ctx, conversationID, userIDs, maxSeq)
return pbconv.SetConversationMaxSeqCaller.Execute(ctx, &pbconv.SetConversationMaxSeqReq{
ConversationID: conversationID,
OwnerUserID: userIDs,
MaxSeq: maxSeq,
})
} }
func unmarshalNotificationElem(bytes []byte, t any) error { func unmarshalNotificationElem(bytes []byte, t any) error {
@ -425,6 +434,5 @@ func unmarshalNotificationElem(bytes []byte, t any) error {
if err := json.Unmarshal(bytes, &notification); err != nil { if err := json.Unmarshal(bytes, &notification); err != nil {
return err return err
} }
return json.Unmarshal([]byte(notification.Detail), t) return json.Unmarshal([]byte(notification.Detail), t)
} }

@ -17,6 +17,7 @@ package auth
import ( import (
"context" "context"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" redis2 "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
@ -28,7 +29,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
pbauth "github.com/openimsdk/protocol/auth" pbauth "github.com/openimsdk/protocol/auth"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/msggateway" "github.com/openimsdk/protocol/msggateway"
@ -44,6 +44,7 @@ type authServer struct {
authDatabase controller.AuthDatabase authDatabase controller.AuthDatabase
RegisterCenter discovery.SvcDiscoveryRegistry RegisterCenter discovery.SvcDiscoveryRegistry
config *Config config *Config
userClient *rpcli.UserClient
} }
type Config struct { type Config struct {
@ -58,6 +59,10 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
if err != nil { if err != nil {
return err return err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
pbauth.RegisterAuthServer(server, &authServer{ pbauth.RegisterAuthServer(server, &authServer{
RegisterCenter: client, RegisterCenter: client,
authDatabase: controller.NewAuthDatabase( authDatabase: controller.NewAuthDatabase(
@ -67,7 +72,8 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
config.Share.MultiLogin, config.Share.MultiLogin,
config.Share.IMAdminUserID, config.Share.IMAdminUserID,
), ),
config: config, config: config,
userClient: rpcli.NewUserClient(userConn),
}) })
return nil return nil
} }
@ -83,7 +89,7 @@ func (s *authServer) GetAdminToken(ctx context.Context, req *pbauth.GetAdminToke
} }
if _, err := rpcclient.GetUserInfo(ctx, req.UserID); err != nil { if err := s.userClient.CheckUser(ctx, []string{req.UserID}); err != nil {
return nil, err return nil, err
} }
@ -112,7 +118,7 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR
if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) { if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) {
return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token") return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token")
} }
if _, err := rpcclient.GetUserInfo(ctx, req.UserID); err != nil { if err := s.userClient.CheckUser(ctx, []string{req.UserID}); err != nil {
return nil, err return nil, err
} }
token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID)) token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID))
@ -153,10 +159,7 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim
return nil, servererrs.ErrTokenNotExist.Wrap() return nil, servererrs.ErrTokenNotExist.Wrap()
} }
func (s *authServer) ParseToken( func (s *authServer) ParseToken(ctx context.Context, req *pbauth.ParseTokenReq) (resp *pbauth.ParseTokenResp, err error) {
ctx context.Context,
req *pbauth.ParseTokenReq,
) (resp *pbauth.ParseTokenResp, err error) {
resp = &pbauth.ParseTokenResp{} resp = &pbauth.ParseTokenResp{}
claims, err := s.parseToken(ctx, req.Token) claims, err := s.parseToken(ctx, req.Token)
if err != nil { if err != nil {

@ -16,6 +16,7 @@ package conversation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"sort" "sort"
"time" "time"
@ -26,15 +27,11 @@ import (
dbModel "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" dbModel "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
pbgroup "github.com/openimsdk/protocol/group"
pbmsg "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/db/redisutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconversation "github.com/openimsdk/protocol/conversation" pbconversation "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
@ -52,6 +49,10 @@ type conversationServer struct {
conversationNotificationSender *ConversationNotificationSender conversationNotificationSender *ConversationNotificationSender
config *Config config *Config
userClient *rpcli.UserClient
msgClient *rpcli.MsgClient
groupClient *rpcli.GroupClient
} }
type Config struct { type Config struct {
@ -77,11 +78,27 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
if err != nil { if err != nil {
return err return err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return err
}
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return err
}
msgClient := rpcli.NewMsgClient(msgConn)
localcache.InitLocalCache(&config.LocalCacheConfig) localcache.InitLocalCache(&config.LocalCacheConfig)
pbconversation.RegisterConversationServer(server, &conversationServer{ pbconversation.RegisterConversationServer(server, &conversationServer{
conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig), conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, msgClient),
conversationDatabase: controller.NewConversationDatabase(conversationDB, conversationDatabase: controller.NewConversationDatabase(conversationDB,
redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()), redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
userClient: rpcli.NewUserClient(userConn),
groupClient: rpcli.NewGroupClient(groupConn),
msgClient: msgClient,
}) })
return nil return nil
} }
@ -118,19 +135,12 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
if len(conversations) == 0 { if len(conversations) == 0 {
return nil, errs.ErrRecordNotFound.Wrap() return nil, errs.ErrRecordNotFound.Wrap()
} }
maxSeqs, err := c.msgClient.GetMaxSeqs(ctx, conversationIDs)
maxSeqs, err := rpccall.ExtractField(ctx, pbmsg.GetMaxSeqsCaller.Invoke,
&pbmsg.GetMaxSeqsReq{ConversationIDs: conversationIDs},
(*pbmsg.SeqsInfoResp).GetMaxSeqs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
chatLogs, err := rpccall.ExtractField(ctx, pbmsg.GetMsgByConversationIDsCaller.Invoke, chatLogs, err := c.msgClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
&pbmsg.GetMsgByConversationIDsReq{
ConversationIDs: conversationIDs,
MaxSeqs: maxSeqs,
}, (*pbmsg.GetMsgByConversationIDsResp).GetMsgDatas)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -140,9 +150,7 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
return nil, err return nil, err
} }
hasReadSeqs, err := rpccall.ExtractField(ctx, pbmsg.GetHasReadSeqsCaller.Invoke, hasReadSeqs, err := c.msgClient.GetHasReadSeqs(ctx, conversationIDs, req.UserID)
&pbmsg.GetHasReadSeqsReq{ConversationIDs: conversationIDs},
(*pbmsg.SeqsInfoResp).GetMaxSeqs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -230,14 +238,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
return nil, errs.ErrArgs.WrapMsg("conversation must not be nil") return nil, errs.ErrArgs.WrapMsg("conversation must not be nil")
} }
if req.Conversation.ConversationType == constant.WriteGroupChatType { if req.Conversation.ConversationType == constant.WriteGroupChatType {
groupInfo, err := rpccall.ExtractField(ctx, pbgroup.GetGroupsInfoCaller.Invoke, groupInfo, err := c.groupClient.GetGroupInfo(ctx, req.Conversation.GroupID)
&pbgroup.GetGroupsInfoReq{GroupIDs: []string{req.Conversation.GroupID}},
func(r *pbgroup.GetGroupsInfoResp) *sdkws.GroupInfo {
if len(r.GroupInfos) > 0 {
return r.GroupInfos[0]
}
return nil
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -444,14 +445,14 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
return nil, err return nil, err
} }
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID) conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID)
if _, err := pbmsg.SetUserConversationMaxSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: conversationID, OwnerUserID: req.UserIDs, MaxSeq: 0}); err != nil { if err := c.msgClient.SetUserConversationMaxSeq(ctx, conversationID, req.UserIDs, 0); err != nil {
return nil, err return nil, err
} }
return &pbconversation.CreateGroupChatConversationsResp{}, nil return &pbconversation.CreateGroupChatConversationsResp{}, nil
} }
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) { func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
if _, err := pbmsg.SetUserConversationMaxSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MaxSeq: req.MaxSeq}); err != nil { if err := c.msgClient.SetUserConversationMaxSeq(ctx, req.ConversationID, req.OwnerUserID, req.MaxSeq); err != nil {
return nil, err return nil, err
} }
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID, if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
@ -465,7 +466,7 @@ func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbc
} }
func (c *conversationServer) SetConversationMinSeq(ctx context.Context, req *pbconversation.SetConversationMinSeqReq) (*pbconversation.SetConversationMinSeqResp, error) { func (c *conversationServer) SetConversationMinSeq(ctx context.Context, req *pbconversation.SetConversationMinSeqReq) (*pbconversation.SetConversationMinSeqResp, error) {
if _, err := pbmsg.SetUserConversationMinSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMinSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MinSeq: req.MinSeq}); err != nil { if err := c.msgClient.SetUserConversationMin(ctx, req.ConversationID, req.OwnerUserID, req.MinSeq); err != nil {
return nil, err return nil, err
} }
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID, if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
@ -575,7 +576,7 @@ func (c *conversationServer) getConversationInfo(
} }
} }
if len(sendIDs) != 0 { if len(sendIDs) != 0 {
sendInfos, err := rpcclient.GetUsersInfo(ctx, sendIDs) sendInfos, err := c.userClient.GetUsersInfo(ctx, sendIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -584,9 +585,7 @@ func (c *conversationServer) getConversationInfo(
} }
} }
if len(groupIDs) != 0 { if len(groupIDs) != 0 {
groupInfos, err := rpccall.ExtractField(ctx, pbgroup.GetGroupsInfoCaller.Invoke, groupInfos, err := c.groupClient.GetGroupsInfo(ctx, groupIDs)
&pbgroup.GetGroupsInfoReq{GroupIDs: groupIDs},
(*pbgroup.GetGroupsInfoResp).GetGroupInfos)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -763,3 +762,51 @@ func (c *conversationServer) GetPinnedConversationIDs(ctx context.Context, req *
} }
return &pbconversation.GetPinnedConversationIDsResp{ConversationIDs: conversationIDs}, nil return &pbconversation.GetPinnedConversationIDsResp{ConversationIDs: conversationIDs}, nil
} }
func (c *conversationServer) ClearUserConversationMsg(ctx context.Context, req *pbconversation.ClearUserConversationMsgReq) (*pbconversation.ClearUserConversationMsgResp, error) {
conversations, err := c.conversationDatabase.FindRandConversation(ctx, req.Timestamp, int(req.Limit))
if err != nil {
return nil, err
}
latestMsgDestructTime := time.UnixMilli(req.Timestamp)
for i, conversation := range conversations {
if conversation.IsMsgDestruct == false || conversation.MsgDestructTime == 0 {
continue
}
seq, err := c.msgClient.GetLastMessageSeqByTime(ctx, conversation.ConversationID, req.Timestamp-conversation.MsgDestructTime)
if err != nil {
return nil, err
}
if seq <= 0 {
log.ZDebug(ctx, "ClearUserConversationMsg GetLastMessageSeqByTime seq <= 0", "index", i, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID, "msgDestructTime", conversation.MsgDestructTime, "seq", seq)
if err := c.setConversationMinSeqAndLatestMsgDestructTime(ctx, conversation.ConversationID, conversation.OwnerUserID, -1, latestMsgDestructTime); err != nil {
return nil, err
}
continue
}
seq++
if err := c.setConversationMinSeqAndLatestMsgDestructTime(ctx, conversation.ConversationID, conversation.OwnerUserID, seq, latestMsgDestructTime); err != nil {
return nil, err
}
log.ZDebug(ctx, "ClearUserConversationMsg set min seq", "index", i, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID, "seq", seq, "msgDestructTime", conversation.MsgDestructTime)
}
return &pbconversation.ClearUserConversationMsgResp{Count: int32(len(conversations))}, nil
}
func (c *conversationServer) setConversationMinSeqAndLatestMsgDestructTime(ctx context.Context, conversationID string, ownerUserID string, minSeq int64, latestMsgDestructTime time.Time) error {
update := map[string]any{
"latest_msg_destruct_time": latestMsgDestructTime,
}
if minSeq >= 0 {
if err := c.msgClient.SetUserConversationMin(ctx, conversationID, []string{ownerUserID}, minSeq); err != nil {
return err
}
update["min_seq"] = minSeq
}
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{ownerUserID}, conversationID, update); err != nil {
return err
}
c.conversationNotificationSender.ConversationChangeNotification(ctx, ownerUserID, []string{conversationID})
return nil
}

@ -16,9 +16,11 @@ package conversation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
) )
@ -27,8 +29,10 @@ type ConversationNotificationSender struct {
*rpcclient.NotificationSender *rpcclient.NotificationSender
} }
func NewConversationNotificationSender(conf *config.Notification) *ConversationNotificationSender { func NewConversationNotificationSender(conf *config.Notification, msgClient *rpcli.MsgClient) *ConversationNotificationSender {
return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient())} return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
return msgClient.SendMsg(ctx, req)
}))}
} }
// SetPrivate invote. // SetPrivate invote.

@ -17,6 +17,7 @@ package group
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"math/big" "math/big"
"math/rand" "math/rand"
"strconv" "strconv"
@ -35,14 +36,10 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook" "github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
"github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification/grouphash"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconv "github.com/openimsdk/protocol/conversation" pbconv "github.com/openimsdk/protocol/conversation"
pbgroup "github.com/openimsdk/protocol/group" pbgroup "github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/wrapperspb" "github.com/openimsdk/protocol/wrapperspb"
"github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/mongoutil"
@ -59,10 +56,13 @@ import (
type groupServer struct { type groupServer struct {
pbgroup.UnimplementedGroupServer pbgroup.UnimplementedGroupServer
db controller.GroupDatabase db controller.GroupDatabase
notification *GroupNotificationSender notification *NotificationSender
config *Config config *Config
webhookClient *webhook.Client webhookClient *webhook.Client
userClient *rpcli.UserClient
msgClient *rpcli.MsgClient
conversationClient *rpcli.ConversationClient
} }
type Config struct { type Config struct {
@ -97,24 +97,33 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
if err != nil { if err != nil {
return err return err
} }
var gs groupServer
database := controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
gs.db = database
gs.notification = NewGroupNotificationSender(
database,
config,
func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {
users, err := rpcclient.GetUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil //userRpcClient := rpcclient.NewUserRpcClient(client, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
}, //msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Share.RpcRegisterName.Msg)
) //conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Share.RpcRegisterName.Conversation)
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return err
}
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
if err != nil {
return err
}
gs := groupServer{
config: config,
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
userClient: rpcli.NewUserClient(userConn),
msgClient: rpcli.NewMsgClient(msgConn),
conversationClient: rpcli.NewConversationClient(conversationConn),
}
gs.db = controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
gs.notification = NewNotificationSender(gs.db, config, gs.userClient, gs.msgClient, gs.conversationClient)
localcache.InitLocalCache(&config.LocalCacheConfig) localcache.InitLocalCache(&config.LocalCacheConfig)
gs.config = config
gs.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
pbgroup.RegisterGroupServer(server, &gs) pbgroup.RegisterGroupServer(server, &gs)
return nil return nil
} }
@ -158,19 +167,6 @@ func (g *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error
return nil return nil
} }
func (g *groupServer) GetPublicUserInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.PublicUserInfo, error) {
if len(userIDs) == 0 {
return map[string]*sdkws.PublicUserInfo{}, nil
}
users, err := rpcclient.GetPublicUserInfos(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.SliceToMapAny(users, func(e *sdkws.PublicUserInfo) (string, *sdkws.PublicUserInfo) {
return e.UserID, e
}), nil
}
func (g *groupServer) IsNotFound(err error) bool { func (g *groupServer) IsNotFound(err error) bool {
return errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err))) return errs.ErrRecordNotFound.Is(specialerror.ErrCode(errs.Unwrap(err)))
} }
@ -212,7 +208,6 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
return nil, errs.ErrArgs.WrapMsg("no group owner") return nil, errs.ErrArgs.WrapMsg("no group owner")
} }
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, g.config.Share.IMAdminUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.OwnerUserID, g.config.Share.IMAdminUserID); err != nil {
return nil, err return nil, err
} }
userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID) userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID)
@ -225,7 +220,7 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
return nil, errs.ErrArgs.WrapMsg("group member repeated") return nil, errs.ErrArgs.WrapMsg("group member repeated")
} }
userMap, err := rpcclient.GetUsersInfoMap(ctx, userIDs) userMap, err := g.userClient.GetUsersInfoMap(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -376,7 +371,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed") return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed")
} }
userMap, err := rpcclient.GetUsersInfoMap(ctx, req.InvitedUserIDs) userMap, err := g.userClient.GetUsersInfoMap(ctx, req.InvitedUserIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -687,7 +682,7 @@ func (g *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.
userIDs = append(userIDs, gr.UserID) userIDs = append(userIDs, gr.UserID)
} }
userIDs = datautil.Distinct(userIDs) userIDs = datautil.Distinct(userIDs)
userMap, err := rpcclient.GetPublicUserInfoMap(ctx, userIDs) userMap, err := g.userClient.GetUsersInfoMap(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -799,7 +794,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
} else if !g.IsNotFound(err) { } else if !g.IsNotFound(err) {
return nil, err return nil, err
} }
if _, err := rpcclient.GetPublicUserInfo(ctx, req.FromUserID); err != nil { if err := g.userClient.CheckUser(ctx, []string{req.FromUserID}); err != nil {
return nil, err return nil, err
} }
var member *model.GroupMember var member *model.GroupMember
@ -843,7 +838,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
} }
func (g *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) { func (g *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) {
user, err := rpcclient.GetUserInfo(ctx, req.InviterUserID) user, err := g.userClient.GetUserInfo(ctx, req.InviterUserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -950,18 +945,11 @@ func (g *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
func (g *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error { func (g *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke, maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
(*msg.GetConversationMaxSeqResp).GetMaxSeq)
if err != nil { if err != nil {
return err return err
} }
return g.conversationClient.SetConversationMaxSeq(ctx, conversationID, userIDs, maxSeq)
return pbconv.SetConversationMaxSeqCaller.Execute(ctx, &pbconv.SetConversationMaxSeqReq{
ConversationID: conversationID,
OwnerUserID: userIDs,
MaxSeq: maxSeq,
})
} }
func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) { func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
@ -1037,11 +1025,7 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
return return
} }
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
if err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
UserIDs: resp.UserIDs,
Conversation: conversation,
}); err != nil {
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation) log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
} }
}() }()
@ -1154,11 +1138,7 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
} }
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
if err := g.conversationClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
if err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
UserIDs: resp.UserIDs,
Conversation: conversation,
}); err != nil {
log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation) log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
} }
}() }()
@ -1310,7 +1290,7 @@ func (g *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGr
} }
func (g *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) { func (g *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) {
user, err := rpcclient.GetPublicUserInfo(ctx, req.UserID) user, err := g.userClient.GetUserInfo(ctx, req.UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1766,7 +1746,7 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *
return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ",")) return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ","))
} }
userMap, err := rpcclient.GetPublicUserInfoMap(ctx, req.UserIDs) userMap, err := g.userClient.GetUsersInfoMap(ctx, req.UserIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1797,7 +1777,7 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *
ownerUserID = owner.UserID ownerUserID = owner.UserID
} }
var userInfo *sdkws.PublicUserInfo var userInfo *sdkws.UserInfo
if user, ok := userMap[e.UserID]; !ok { if user, ok := userMap[e.UserID]; !ok {
userInfo = user userInfo = user
} }
@ -1843,7 +1823,7 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
return nil, err return nil, err
} }
userInfos, err := rpcclient.GetPublicUserInfos(ctx, []string{req.UserID}) userInfos, err := g.userClient.GetUsersInfo(ctx, []string{req.UserID})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -18,6 +18,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
@ -28,13 +29,11 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/notification/common_user"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconv "github.com/openimsdk/protocol/conversation"
pbgroup "github.com/openimsdk/protocol/group" pbgroup "github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
@ -50,27 +49,38 @@ const (
adminReceiver adminReceiver
) )
func NewGroupNotificationSender( func NewNotificationSender(db controller.GroupDatabase, config *Config, userClient *rpcli.UserClient, msgClient *rpcli.MsgClient, conversationClient *rpcli.ConversationClient) *NotificationSender {
db controller.GroupDatabase, return &NotificationSender{
config *Config, NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig,
fn func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error), rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
) *GroupNotificationSender { return msgClient.SendMsg(ctx, req)
return &GroupNotificationSender{ }),
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(), rpcclient.WithUserRpcClient()), rpcclient.WithUserRpcClient(userClient.GetUserInfo),
getUsersInfo: fn, ),
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, db: db,
config: config, config: config,
msgClient: msgClient,
conversationClient: conversationClient,
} }
} }
type GroupNotificationSender struct { type NotificationSender struct {
*rpcclient.NotificationSender *rpcclient.NotificationSender
getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
db controller.GroupDatabase db controller.GroupDatabase
config *Config config *Config
msgClient *rpcli.MsgClient
conversationClient *rpcli.ConversationClient
} }
func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error { func (g *NotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error {
if len(members) == 0 { if len(members) == 0 {
return nil return nil
} }
@ -85,7 +95,7 @@ func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, membe
if err != nil { if err != nil {
return err return err
} }
userMap := make(map[string]notification.CommonUser) userMap := make(map[string]common_user.CommonUser)
for i, user := range users { for i, user := range users {
userMap[user.GetUserID()] = users[i] userMap[user.GetUserID()] = users[i]
} }
@ -105,7 +115,7 @@ func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, membe
return nil return nil
} }
func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) { func (g *NotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
users, err := g.getUsersInfo(ctx, []string{userID}) users, err := g.getUsersInfo(ctx, []string{userID})
if err != nil { if err != nil {
return nil, err return nil, err
@ -121,7 +131,7 @@ func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (*
}, nil }, nil
} }
func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) { func (g *NotificationSender) getGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
gm, err := g.db.TakeGroup(ctx, groupID) gm, err := g.db.TakeGroup(ctx, groupID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -142,7 +152,7 @@ func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID stri
return convert.Db2PbGroupInfo(gm, ownerUserID, num), nil return convert.Db2PbGroupInfo(gm, ownerUserID, num), nil
} }
func (g *GroupNotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { func (g *NotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) {
members, err := g.db.FindGroupMembers(ctx, groupID, userIDs) members, err := g.db.FindGroupMembers(ctx, groupID, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -158,7 +168,7 @@ func (g *GroupNotificationSender) getGroupMembers(ctx context.Context, groupID s
return res, nil return res, nil
} }
func (g *GroupNotificationSender) getGroupMemberMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) { func (g *NotificationSender) getGroupMemberMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) {
members, err := g.getGroupMembers(ctx, groupID, userIDs) members, err := g.getGroupMembers(ctx, groupID, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -170,7 +180,7 @@ func (g *GroupNotificationSender) getGroupMemberMap(ctx context.Context, groupID
return m, nil return m, nil
} }
func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) { func (g *NotificationSender) getGroupMember(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) {
members, err := g.getGroupMembers(ctx, groupID, []string{userID}) members, err := g.getGroupMembers(ctx, groupID, []string{userID})
if err != nil { if err != nil {
return nil, err return nil, err
@ -181,7 +191,7 @@ func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID st
return members[0], nil return members[0], nil
} }
func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) { func (g *NotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) {
members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin}) members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin})
if err != nil { if err != nil {
return nil, err return nil, err
@ -193,7 +203,7 @@ func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Contex
return datautil.Slice(members, fn), nil return datautil.Slice(members, fn), nil
} }
func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo { func (g *NotificationSender) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
return &sdkws.GroupMemberFullInfo{ return &sdkws.GroupMemberFullInfo{
GroupID: member.GroupID, GroupID: member.GroupID,
UserID: member.UserID, UserID: member.UserID,
@ -210,7 +220,7 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, ap
} }
} }
/* func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) { /* func (g *NotificationSender) getUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
users, err := g.getUsersInfo(ctx, userIDs) users, err := g.getUsersInfo(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -222,11 +232,11 @@ func (g *GroupNotificationSender) groupMemberDB2PB(member *model.GroupMember, ap
return result, nil return result, nil
} */ } */
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) { func (g *NotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
return g.fillOpUserByUserID(ctx, mcontext.GetOpUserID(ctx), opUser, groupID) return g.fillOpUserByUserID(ctx, mcontext.GetOpUserID(ctx), opUser, groupID)
} }
func (g *GroupNotificationSender) fillOpUserByUserID(ctx context.Context, userID string, opUser **sdkws.GroupMemberFullInfo, groupID string) error { func (g *NotificationSender) fillOpUserByUserID(ctx context.Context, userID string, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
if opUser == nil { if opUser == nil {
return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil") return errs.ErrInternalServer.WrapMsg("**sdkws.GroupMemberFullInfo is nil")
} }
@ -270,7 +280,7 @@ func (g *GroupNotificationSender) fillOpUserByUserID(ctx context.Context, userID
return nil return nil
} }
func (g *GroupNotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) { func (g *NotificationSender) setVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string) {
versions := versionctx.GetVersionLog(ctx).Get() versions := versionctx.GetVersionLog(ctx).Get()
for _, coll := range versions { for _, coll := range versions {
if coll.Name == collName && coll.Doc.DID == id { if coll.Name == collName && coll.Doc.DID == id {
@ -281,7 +291,7 @@ func (g *GroupNotificationSender) setVersion(ctx context.Context, version *uint6
} }
} }
func (g *GroupNotificationSender) setSortVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string, sortVersion *uint64) { func (g *NotificationSender) setSortVersion(ctx context.Context, version *uint64, versionID *string, collName string, id string, sortVersion *uint64) {
versions := versionctx.GetVersionLog(ctx).Get() versions := versionctx.GetVersionLog(ctx).Get()
for _, coll := range versions { for _, coll := range versions {
if coll.Name == collName && coll.Doc.DID == id { if coll.Name == collName && coll.Doc.DID == id {
@ -296,7 +306,7 @@ func (g *GroupNotificationSender) setSortVersion(ctx context.Context, version *u
} }
} }
func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) { func (g *NotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -310,7 +320,7 @@ func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context,
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupCreatedNotification, tips)
} }
func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) { func (g *NotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -324,7 +334,7 @@ func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context,
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName()) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNotification, tips, rpcclient.WithRpcGetUserName())
} }
func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) { func (g *NotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -338,7 +348,7 @@ func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Conte
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetNameNotification, tips)
} }
func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) { func (g *NotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -352,7 +362,7 @@ func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx conte
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName()) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupInfoSetAnnouncementNotification, tips, rpcclient.WithRpcGetUserName())
} }
func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) { func (g *NotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbgroup.JoinGroupReq) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -380,7 +390,7 @@ func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.C
} }
} }
func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) { func (g *NotificationSender) MemberQuitNotification(ctx context.Context, member *sdkws.GroupMemberFullInfo) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -397,7 +407,7 @@ func (g *GroupNotificationSender) MemberQuitNotification(ctx context.Context, me
g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), member.GroupID, constant.MemberQuitNotification, tips)
} }
func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) { func (g *NotificationSender) GroupApplicationAcceptedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -430,7 +440,7 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte
} }
} }
func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) { func (g *NotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbgroup.GroupApplicationResponseReq) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -463,7 +473,7 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte
} }
} }
func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) { func (g *NotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -494,7 +504,7 @@ func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupOwnerTransferredNotification, tips)
} }
func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) { func (g *NotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -508,7 +518,7 @@ func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context,
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.MemberKickedNotification, tips)
} }
func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, invitedOpUserID string, entrantUserID ...string) error { func (g *NotificationSender) GroupApplicationAgreeMemberEnterNotification(ctx context.Context, groupID string, invitedOpUserID string, entrantUserID ...string) error {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -518,26 +528,15 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
if !g.config.RpcConfig.EnableHistoryForNewMembers { if !g.config.RpcConfig.EnableHistoryForNewMembers {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke, maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
(*msg.GetConversationMaxSeqResp).GetMaxSeq)
if err != nil { if err != nil {
return err return err
} }
if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, entrantUserID, maxSeq); err != nil {
if err := msg.SetUserConversationsMinSeqCaller.Execute(ctx, &msg.SetUserConversationsMinSeqReq{
UserIDs: entrantUserID,
ConversationID: conversationID,
Seq: maxSeq,
}); err != nil {
return err return err
} }
} }
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, entrantUserID); err != nil {
if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{
UserIDs: entrantUserID,
GroupID: groupID,
}); err != nil {
return err return err
} }
@ -573,7 +572,7 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
return nil return nil
} }
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) error { func (g *NotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) error {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -583,28 +582,17 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g
if !g.config.RpcConfig.EnableHistoryForNewMembers { if !g.config.RpcConfig.EnableHistoryForNewMembers {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID) conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke, maxSeq, err := g.msgClient.GetConversationMaxSeq(ctx, conversationID)
&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
(*msg.GetConversationMaxSeqResp).GetMaxSeq)
if err != nil { if err != nil {
return err return err
} }
if err := msg.SetUserConversationsMinSeqCaller.Execute(ctx, &msg.SetUserConversationsMinSeqReq{ if err := g.msgClient.SetUserConversationsMinSeq(ctx, conversationID, []string{entrantUserID}, maxSeq); err != nil {
UserIDs: []string{entrantUserID},
ConversationID: conversationID,
Seq: maxSeq,
}); err != nil {
return err return err
} }
} }
if err := g.conversationClient.CreateGroupChatConversations(ctx, groupID, []string{entrantUserID}); err != nil {
if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{
UserIDs: []string{entrantUserID},
GroupID: groupID,
}); err != nil {
return err return err
} }
var group *sdkws.GroupInfo var group *sdkws.GroupInfo
group, err = g.getGroupInfo(ctx, groupID) group, err = g.getGroupInfo(ctx, groupID)
if err != nil { if err != nil {
@ -625,7 +613,7 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g
return nil return nil
} }
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) { func (g *NotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -638,7 +626,7 @@ func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context
g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), tips.Group.GroupID, constant.GroupDismissedNotification, tips)
} }
func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) { func (g *NotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -666,7 +654,7 @@ func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Conte
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberMutedNotification, tips)
} }
func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) { func (g *NotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -691,7 +679,7 @@ func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberCancelMutedNotification, tips)
} }
func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) { func (g *NotificationSender) GroupMutedNotification(ctx context.Context, groupID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -719,7 +707,7 @@ func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, gr
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMutedNotification, tips)
} }
func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) { func (g *NotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -747,7 +735,7 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupCancelMutedNotification, tips)
} }
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) { func (g *NotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -772,7 +760,7 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberInfoSetNotification, tips)
} }
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) { func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {
@ -796,7 +784,7 @@ func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips) g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
} }
func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) { func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
var err error var err error
defer func() { defer func() {
if err != nil { if err != nil {

@ -2,138 +2,59 @@ package msg
import ( import (
"context" "context"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
pbconv "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/wrapperspb"
"github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext" "strings"
"github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/idutil"
"github.com/openimsdk/tools/utils/stringutil"
"golang.org/x/sync/errgroup"
) )
// hard delete in Database. // DestructMsgs hard delete in Database.
func (m *msgServer) DestructMsgs(ctx context.Context, req *msg.DestructMsgsReq) (_ *msg.DestructMsgsResp, err error) { func (m *msgServer) DestructMsgs(ctx context.Context, req *msg.DestructMsgsReq) (*msg.DestructMsgsResp, error) {
if err := authverify.CheckAdmin(ctx, m.config.Share.IMAdminUserID); err != nil { if err := authverify.CheckAdmin(ctx, m.config.Share.IMAdminUserID); err != nil {
return nil, err return nil, err
} }
if req.Timestamp > time.Now().UnixMilli() { docs, err := m.MsgDatabase.GetRandBeforeMsg(ctx, req.Timestamp, int(req.Limit))
return nil, errs.ErrArgs.WrapMsg("request millisecond timestamp error") if err != nil {
return nil, err
} }
var ( for i, doc := range docs {
docNum int if err := m.MsgDatabase.DeleteDoc(ctx, doc.DocID); err != nil {
msgNum int return nil, err
start = time.Now()
getLimit = 5000
)
destructMsg := func(ctx context.Context) (bool, error) {
docIDs, err := m.MsgDatabase.GetDocIDs(ctx)
if err != nil {
return false, err
} }
log.ZDebug(ctx, "DestructMsgs delete doc", "index", i, "docID", doc.DocID)
msgs, err := m.MsgDatabase.GetBeforeMsg(ctx, req.Timestamp, docIDs, getLimit) index := strings.LastIndex(doc.DocID, ":")
if err != nil { if index < 0 {
return false, err continue
}
if len(msgs) == 0 {
return false, nil
} }
var minSeq int64
for _, msg := range msgs { for _, model := range doc.Msg {
index, err := m.MsgDatabase.DeleteDocMsgBefore(ctx, req.Timestamp, msg) if model.Msg == nil {
if err != nil { continue
return false, err
} }
if len(index) == 0 { if model.Msg.Seq > minSeq {
return false, errs.ErrInternalServer.WrapMsg("delete doc msg failed") minSeq = model.Msg.Seq
} }
docNum++
msgNum += len(index)
} }
if minSeq <= 0 {
return true, nil continue
} }
conversationID := doc.DocID[:index]
_, err = destructMsg(ctx) if conversationID == "" {
if err != nil { continue
log.ZError(ctx, "clear msg failed", err, "docNum", docNum, "msgNum", msgNum, "cost", time.Since(start)) }
return nil, err minSeq++
if err := m.MsgDatabase.SetMinSeq(ctx, conversationID, minSeq); err != nil {
return nil, err
}
log.ZDebug(ctx, "DestructMsgs delete doc set min seq", "index", i, "docID", doc.DocID, "conversationID", conversationID, "setMinSeq", minSeq)
} }
return &msg.DestructMsgsResp{Count: int32(len(docs))}, nil
log.ZDebug(ctx, "clearing message", "docNum", docNum, "msgNum", msgNum, "cost", time.Since(start))
return &msg.DestructMsgsResp{}, nil
} }
// soft delete for user self func (m *msgServer) GetLastMessageSeqByTime(ctx context.Context, req *msg.GetLastMessageSeqByTimeReq) (*msg.GetLastMessageSeqByTimeResp, error) {
func (m *msgServer) ClearMsg(ctx context.Context, req *msg.ClearMsgReq) (_ *msg.ClearMsgResp, err error) { seq, err := m.MsgDatabase.GetLastMessageSeqByTime(ctx, req.ConversationID, req.Time)
temp := convert.ConversationsPb2DB(req.Conversations) if err != nil {
batchNum := 100
errg, _ := errgroup.WithContext(ctx)
errg.SetLimit(100)
for i := 0; i < len(temp); i += batchNum {
batch := temp[i:min(i+batchNum, len(temp))]
errg.Go(func() error {
for _, conversation := range batch {
handleCtx := mcontext.NewCtx(stringutil.GetSelfFuncName() + "-" + idutil.OperationIDGenerator() + "-" + conversation.ConversationID + "-" + conversation.OwnerUserID)
log.ZDebug(handleCtx, "User MsgsDestruct",
"conversationID", conversation.ConversationID,
"ownerUserID", conversation.OwnerUserID,
"msgDestructTime", conversation.MsgDestructTime,
"lastMsgDestructTime", conversation.LatestMsgDestructTime)
seqs, err := m.MsgDatabase.ClearUserMsgs(handleCtx, conversation.OwnerUserID, conversation.ConversationID, conversation.MsgDestructTime, conversation.LatestMsgDestructTime)
if err != nil {
log.ZError(handleCtx, "user msg destruct failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue
}
if len(seqs) > 0 {
minseq := datautil.Max(seqs...)
// update
if err := pbconv.UpdateConversationCaller.Execute(ctx, &pbconv.UpdateConversationReq{
ConversationID: conversation.ConversationID,
UserIDs: []string{conversation.OwnerUserID},
MinSeq: wrapperspb.Int64(minseq),
LatestMsgDestructTime: wrapperspb.Int64(time.Now().UnixMilli()),
}); err != nil {
log.ZError(handleCtx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue
}
if err := pbconv.SetConversationMinSeqCaller.Execute(ctx, &pbconv.SetConversationMinSeqReq{
ConversationID: conversation.ConversationID,
OwnerUserID: []string{conversation.OwnerUserID},
MinSeq: minseq,
}); err != nil {
return err
}
// if you need Notify SDK client userseq is update.
// m.msgNotificationSender.UserDeleteMsgsNotification(handleCtx, conversation.OwnerUserID, conversation.ConversationID, seqs)
}
}
return nil
})
}
if err := errg.Wait(); err != nil {
return nil, err return nil, err
} }
return &msg.GetLastMessageSeqByTimeResp{Seq: seq}, nil
return nil, nil
} }

@ -21,7 +21,6 @@ import (
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/utils/timeutil" "github.com/openimsdk/tools/utils/timeutil"
@ -75,22 +74,13 @@ func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*ms
if err := m.MsgDatabase.DeleteMsgsPhysicalBySeqs(ctx, req.ConversationID, req.Seqs); err != nil { if err := m.MsgDatabase.DeleteMsgsPhysicalBySeqs(ctx, req.ConversationID, req.Seqs); err != nil {
return nil, err return nil, err
} }
conv, err := m.conversationClient.GetConversationsByConversationID(ctx, req.ConversationID)
conversations, err := rpccall.ExtractField(ctx, conversation.GetConversationsByConversationIDCaller.Invoke, &conversation.GetConversationsByConversationIDReq{
ConversationIDs: []string{req.ConversationID},
}, (*conversation.GetConversationsByConversationIDResp).GetConversations)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tips := &sdkws.DeleteMsgsTips{UserID: req.UserID, ConversationID: req.ConversationID, Seqs: req.Seqs} tips := &sdkws.DeleteMsgsTips{UserID: req.UserID, ConversationID: req.ConversationID, Seqs: req.Seqs}
m.notificationSender.NotificationWithSessionType( m.notificationSender.NotificationWithSessionType(ctx, req.UserID, m.conversationAndGetRecvID(conv, req.UserID),
ctx, constant.DeleteMsgsNotification, conv.ConversationType, tips)
req.UserID,
m.conversationAndGetRecvID(conversations[0], req.UserID),
constant.DeleteMsgsNotification,
conversations[0].ConversationType,
tips,
)
} else { } else {
if err := m.MsgDatabase.DeleteUserMsgsBySeqs(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil { if err := m.MsgDatabase.DeleteUserMsgsBySeqs(ctx, req.UserID, req.ConversationID, req.Seqs); err != nil {
return nil, err return nil, err
@ -125,9 +115,7 @@ func (m *msgServer) DeleteMsgPhysical(ctx context.Context, req *msg.DeleteMsgPhy
} }
func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []string, userID string, deleteSyncOpt *msg.DeleteSyncOpt) error { func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []string, userID string, deleteSyncOpt *msg.DeleteSyncOpt) error {
conversations, err := rpccall.ExtractField(ctx, conversation.GetConversationsByConversationIDCaller.Invoke, &conversation.GetConversationsByConversationIDReq{ conversations, err := m.conversationClient.GetConversationsByConversationIDs(ctx, conversationIDs)
ConversationIDs: conversationIDs,
}, (*conversation.GetConversationsByConversationIDResp).GetConversations)
if err != nil { if err != nil {
return err return err
} }
@ -150,11 +138,7 @@ func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []str
} }
ownerUserIDs := []string{userID} ownerUserIDs := []string{userID}
for conversationID, seq := range setSeqs { for conversationID, seq := range setSeqs {
if err := conversation.SetConversationMinSeqCaller.Execute(ctx, &conversation.SetConversationMinSeqReq{ if err := m.conversationClient.SetConversationMinSeq(ctx, conversationID, ownerUserIDs, seq); err != nil {
ConversationID: conversationID,
OwnerUserID: ownerUserIDs,
MinSeq: seq,
}); err != nil {
return err return err
} }
} }

@ -17,7 +17,7 @@ package msg
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
) )

@ -118,25 +118,14 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
} else { // @Everyone and @other people } else { // @Everyone and @other people
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
if err := m.conversationClient.SetConversations(ctx, atUserID, conversation); err != nil {
err = pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
UserIDs: atUserID,
Conversation: conversation,
})
if err != nil {
log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation) log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation)
} }
memberUserIDList = datautil.Single(atUserID, memberUserIDList) memberUserIDList = datautil.Single(atUserID, memberUserIDList)
} }
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
if err := m.conversationClient.SetConversations(ctx, memberUserIDList, conversation); err != nil {
err = pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
UserIDs: memberUserIDList,
Conversation: conversation,
})
if err != nil {
log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation) log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation)
} }
@ -144,11 +133,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
} }
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe}
err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{ if err := m.conversationClient.SetConversations(ctx, msg.AtUserIDList, conversation); err != nil {
UserIDs: msg.AtUserIDList,
Conversation: conversation,
})
if err != nil {
log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation) log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation)
} }
} }

@ -16,6 +16,7 @@ package msg
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
@ -26,8 +27,8 @@ import (
"github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/db/redisutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/open-im-server/v3/pkg/rpccache" "github.com/openimsdk/open-im-server/v3/pkg/rpccache"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
@ -36,39 +37,39 @@ import (
) )
type MessageInterceptorFunc func(ctx context.Context, globalConfig *Config, req *msg.SendMsgReq) (*sdkws.MsgData, error) type MessageInterceptorFunc func(ctx context.Context, globalConfig *Config, req *msg.SendMsgReq) (*sdkws.MsgData, error)
type (
// MessageInterceptorChain defines a chain of message interceptor functions.
MessageInterceptorChain []MessageInterceptorFunc
// MsgServer encapsulates dependencies required for message handling. // MessageInterceptorChain defines a chain of message interceptor functions.
msgServer struct { type MessageInterceptorChain []MessageInterceptorFunc
RegisterCenter discovery.SvcDiscoveryRegistry // Service discovery registry for service registration.
MsgDatabase controller.CommonMsgDatabase // Interface for message database operations.
StreamMsgDatabase controller.StreamMsgDatabase
UserLocalCache *rpccache.UserLocalCache // Local cache for user data.
FriendLocalCache *rpccache.FriendLocalCache // Local cache for friend data.
GroupLocalCache *rpccache.GroupLocalCache // Local cache for group data.
ConversationLocalCache *rpccache.ConversationLocalCache // Local cache for conversation data.
Handlers MessageInterceptorChain // Chain of handlers for processing messages.
notificationSender *rpcclient.NotificationSender // RPC client for sending notifications.
msgNotificationSender *MsgNotificationSender // RPC client for sending msg notifications.
config *Config // Global configuration settings.
webhookClient *webhook.Client
msg.UnimplementedMsgServer
}
Config struct { type Config struct {
RpcConfig config.Msg RpcConfig config.Msg
RedisConfig config.Redis RedisConfig config.Redis
MongodbConfig config.Mongo MongodbConfig config.Mongo
KafkaConfig config.Kafka KafkaConfig config.Kafka
NotificationConfig config.Notification NotificationConfig config.Notification
Share config.Share Share config.Share
WebhooksConfig config.Webhooks WebhooksConfig config.Webhooks
LocalCacheConfig config.LocalCache LocalCacheConfig config.LocalCache
Discovery config.Discovery Discovery config.Discovery
} }
)
// MsgServer encapsulates dependencies required for message handling.
type msgServer struct {
msg.UnimplementedMsgServer
RegisterCenter discovery.SvcDiscoveryRegistry // Service discovery registry for service registration.
MsgDatabase controller.CommonMsgDatabase // Interface for message database operations.
StreamMsgDatabase controller.StreamMsgDatabase
UserLocalCache *rpccache.UserLocalCache // Local cache for user data.
FriendLocalCache *rpccache.FriendLocalCache // Local cache for friend data.
GroupLocalCache *rpccache.GroupLocalCache // Local cache for group data.
ConversationLocalCache *rpccache.ConversationLocalCache // Local cache for conversation data.
Handlers MessageInterceptorChain // Chain of handlers for processing messages.
notificationSender *rpcclient.NotificationSender // RPC client for sending notifications.
msgNotificationSender *MsgNotificationSender // RPC client for sending msg notifications.
config *Config // Global configuration settings.
webhookClient *webhook.Client
conversationClient *rpcli.ConversationClient
}
func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorFunc) { func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorFunc) {
m.Handlers = append(m.Handlers, interceptorFunc...) m.Handlers = append(m.Handlers, interceptorFunc...)
@ -107,16 +108,34 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
if err != nil { if err != nil {
return err return err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return err
}
friendConn, err := client.GetConn(ctx, config.Discovery.RpcService.Friend)
if err != nil {
return err
}
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
if err != nil {
return err
}
conversationClient := rpcli.NewConversationClient(conversationConn)
s := &msgServer{ s := &msgServer{
MsgDatabase: msgDatabase, MsgDatabase: msgDatabase,
StreamMsgDatabase: controller.NewStreamMsgDatabase(streamMsg), StreamMsgDatabase: controller.NewStreamMsgDatabase(streamMsg),
RegisterCenter: client, RegisterCenter: client,
UserLocalCache: rpccache.NewUserLocalCache(&config.LocalCacheConfig, rdb), UserLocalCache: rpccache.NewUserLocalCache(rpcli.NewUserClient(userConn), &config.LocalCacheConfig, rdb),
GroupLocalCache: rpccache.NewGroupLocalCache(&config.LocalCacheConfig, rdb), GroupLocalCache: rpccache.NewGroupLocalCache(rpcli.NewGroupClient(groupConn), &config.LocalCacheConfig, rdb),
ConversationLocalCache: rpccache.NewConversationLocalCache(&config.LocalCacheConfig, rdb), ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, &config.LocalCacheConfig, rdb),
FriendLocalCache: rpccache.NewFriendLocalCache(&config.LocalCacheConfig, rdb), FriendLocalCache: rpccache.NewFriendLocalCache(rpcli.NewRelationClient(friendConn), &config.LocalCacheConfig, rdb),
config: config, config: config,
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
conversationClient: conversationClient,
} }
s.notificationSender = rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithLocalSendMsg(s.SendMsg)) s.notificationSender = rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithLocalSendMsg(s.SendMsg))

@ -8,9 +8,7 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
pbconv "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
) )
@ -74,10 +72,7 @@ func (m *msgServer) AppendStreamMsg(ctx context.Context, req *msg.AppendStreamMs
if err := m.StreamMsgDatabase.AppendStreamMsg(ctx, req.ClientMsgID, int(req.StartIndex), req.Packets, req.End, deadlineTime); err != nil { if err := m.StreamMsgDatabase.AppendStreamMsg(ctx, req.ClientMsgID, int(req.StartIndex), req.Packets, req.End, deadlineTime); err != nil {
return nil, err return nil, err
} }
conversation, err := rpccall.ExtractField(ctx, pbconv.GetConversationCaller.Invoke, &pbconv.GetConversationReq{ conversation, err := m.conversationClient.GetConversation(ctx, res.ConversationID, res.UserID)
ConversationID: res.ConversationID,
OwnerUserID: res.UserID,
}, (*pbconv.GetConversationResp).GetConversation)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -21,7 +21,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
@ -39,7 +38,7 @@ func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *relation.Ge
return nil, err return nil, err
} }
resp = &relation.GetPaginationBlacksResp{} resp = &relation.GetPaginationBlacksResp{}
resp.Blacks, err = convert.BlackDB2Pb(ctx, blacks, rpcclient.GetUsersInfoMap) resp.Blacks, err = convert.BlackDB2Pb(ctx, blacks, s.userClient.GetUsersInfoMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -81,9 +80,7 @@ func (s *friendServer) AddBlack(ctx context.Context, req *relation.AddBlackReq)
if err := s.webhookBeforeAddBlack(ctx, &s.config.WebhooksConfig.BeforeAddBlack, req); err != nil { if err := s.webhookBeforeAddBlack(ctx, &s.config.WebhooksConfig.BeforeAddBlack, req); err != nil {
return nil, err return nil, err
} }
if err := s.userClient.CheckUser(ctx, []string{req.OwnerUserID, req.BlackUserID}); err != nil {
_, err := rpcclient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID})
if err != nil {
return nil, err return nil, err
} }
black := model.Black{ black := model.Black{
@ -114,7 +111,7 @@ func (s *friendServer) GetSpecifiedBlacks(ctx context.Context, req *relation.Get
return nil, errs.ErrArgs.WrapMsg("userIDList repeated") return nil, errs.ErrArgs.WrapMsg("userIDList repeated")
} }
userMap, err := rpcclient.GetPublicUserInfoMap(ctx, req.UserIDList) userMap, err := s.userClient.GetUsersInfoMap(ctx, req.UserIDList)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -132,13 +129,26 @@ func (s *friendServer) GetSpecifiedBlacks(ctx context.Context, req *relation.Get
Blacks: make([]*sdkws.BlackInfo, 0, len(req.UserIDList)), Blacks: make([]*sdkws.BlackInfo, 0, len(req.UserIDList)),
} }
toPublcUser := func(userID string) *sdkws.PublicUserInfo {
v, ok := userMap[userID]
if !ok {
return nil
}
return &sdkws.PublicUserInfo{
UserID: v.UserID,
Nickname: v.Nickname,
FaceURL: v.FaceURL,
Ex: v.Ex,
}
}
for _, userID := range req.UserIDList { for _, userID := range req.UserIDList {
if black := blackMap[userID]; black != nil { if black := blackMap[userID]; black != nil {
resp.Blacks = append(resp.Blacks, resp.Blacks = append(resp.Blacks,
&sdkws.BlackInfo{ &sdkws.BlackInfo{
OwnerUserID: black.OwnerUserID, OwnerUserID: black.OwnerUserID,
CreateTime: black.CreateTime.UnixMilli(), CreateTime: black.CreateTime.UnixMilli(),
BlackUserInfo: userMap[userID], BlackUserInfo: toPublcUser(userID),
AddSource: black.AddSource, AddSource: black.AddSource,
OperatorUserID: black.OperatorUserID, OperatorUserID: black.OperatorUserID,
Ex: black.Ex, Ex: black.Ex,

@ -16,6 +16,7 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/tools/mq/memamq" "github.com/openimsdk/tools/mq/memamq"
@ -31,7 +32,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
@ -51,6 +51,7 @@ type friendServer struct {
config *Config config *Config
webhookClient *webhook.Client webhookClient *webhook.Client
queue *memamq.MemoryQueue queue *memamq.MemoryQueue
userClient *rpcli.UserClient
} }
type Config struct { type Config struct {
@ -90,10 +91,21 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
return err return err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return err
}
userClient := rpcli.NewUserClient(userConn)
// Initialize notification sender // Initialize notification sender
notificationSender := NewFriendNotificationSender( notificationSender := NewFriendNotificationSender(
&config.NotificationConfig, &config.NotificationConfig,
WithRpcFunc(rpcclient.GetUsersInfo), rpcli.NewMsgClient(msgConn),
WithRpcFunc(userClient.GetUsersInfo),
) )
localcache.InitLocalCache(&config.LocalCacheConfig) localcache.InitLocalCache(&config.LocalCacheConfig)
@ -114,6 +126,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
config: config, config: config,
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
queue: memamq.NewMemoryQueue(16, 1024*1024), queue: memamq.NewMemoryQueue(16, 1024*1024),
userClient: userClient,
}) })
return nil return nil
} }
@ -130,7 +143,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *relation.Apply
if err = s.webhookBeforeAddFriend(ctx, &s.config.WebhooksConfig.BeforeAddFriend, req); err != nil && err != servererrs.ErrCallbackContinue { if err = s.webhookBeforeAddFriend(ctx, &s.config.WebhooksConfig.BeforeAddFriend, req); err != nil && err != servererrs.ErrCallbackContinue {
return nil, err return nil, err
} }
if _, err := rpcclient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { if err := s.userClient.CheckUser(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
return nil, err return nil, err
} }
@ -155,7 +168,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *relation.ImportFr
return nil, err return nil, err
} }
if _, err := rpcclient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil { if err := s.userClient.CheckUser(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil {
return nil, err return nil, err
} }
if datautil.Contain(req.OwnerUserID, req.FriendUserIDs...) { if datautil.Contain(req.OwnerUserID, req.FriendUserIDs...) {
@ -296,7 +309,7 @@ func (s *friendServer) getFriend(ctx context.Context, ownerUserID string, friend
if err != nil { if err != nil {
return nil, err return nil, err
} }
return convert.FriendsDB2Pb(ctx, friends, rpcclient.GetUsersInfoMap) return convert.FriendsDB2Pb(ctx, friends, s.userClient.GetUsersInfoMap)
} }
// Get the list of friend requests sent out proactively. // Get the list of friend requests sent out proactively.
@ -308,7 +321,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
return nil, err return nil, err
} }
resp = &relation.GetDesignatedFriendsApplyResp{} resp = &relation.GetDesignatedFriendsApplyResp{}
resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap) resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userClient.GetUsersInfoMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -327,7 +340,7 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *rel
} }
resp = &relation.GetPaginationFriendsApplyToResp{} resp = &relation.GetPaginationFriendsApplyToResp{}
resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap) resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userClient.GetUsersInfoMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -349,7 +362,7 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *r
return nil, err return nil, err
} }
resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap) resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userClient.GetUsersInfoMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -380,7 +393,7 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *relation.G
} }
resp = &relation.GetPaginationFriendsResp{} resp = &relation.GetPaginationFriendsResp{}
resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, rpcclient.GetUsersInfoMap) resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, s.userClient.GetUsersInfoMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -413,7 +426,7 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *relatio
return nil, errs.ErrArgs.WrapMsg("userIDList repeated") return nil, errs.ErrArgs.WrapMsg("userIDList repeated")
} }
userMap, err := rpcclient.GetUsersInfoMap(ctx, req.UserIDList) userMap, err := s.userClient.GetUsersInfoMap(ctx, req.UserIDList)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -517,18 +530,3 @@ func (s *friendServer) UpdateFriends(
s.notificationSender.FriendsInfoUpdateNotification(ctx, req.OwnerUserID, req.FriendUserIDs) s.notificationSender.FriendsInfoUpdateNotification(ctx, req.OwnerUserID, req.FriendUserIDs)
return resp, nil return resp, nil
} }
func (s *friendServer) GetIncrementalFriendsApplyTo(ctx context.Context, req *relation.GetIncrementalFriendsApplyToReq) (*relation.GetIncrementalFriendsApplyToResp, error) {
// TODO implement me
return nil, nil
}
func (s *friendServer) GetIncrementalFriendsApplyFrom(ctx context.Context, req *relation.GetIncrementalFriendsApplyFromReq) (*relation.GetIncrementalFriendsApplyFromResp, error) {
// TODO implement me
return nil, nil
}
func (s *friendServer) GetIncrementalBlacks(ctx context.Context, req *relation.GetIncrementalBlacksReq) (*relation.GetIncrementalBlacksResp, error) {
// TODO implement me
return nil, nil
}

@ -16,6 +16,8 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
@ -25,8 +27,8 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/notification/common_user"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
@ -36,7 +38,7 @@ import (
type FriendNotificationSender struct { type FriendNotificationSender struct {
*rpcclient.NotificationSender *rpcclient.NotificationSender
// Target not found err // Target not found err
getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
// db controller // db controller
db controller.FriendDatabase db controller.FriendDatabase
} }
@ -53,7 +55,7 @@ func WithDBFunc(
fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error), fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error),
) friendNotificationSenderOptions { ) friendNotificationSenderOptions {
return func(s *FriendNotificationSender) { return func(s *FriendNotificationSender) {
f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { f := func(ctx context.Context, userIDs []string) (result []common_user.CommonUser, err error) {
users, err := fn(ctx, userIDs) users, err := fn(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -71,7 +73,7 @@ func WithRpcFunc(
fn func(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error), fn func(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error),
) friendNotificationSenderOptions { ) friendNotificationSenderOptions {
return func(s *FriendNotificationSender) { return func(s *FriendNotificationSender) {
f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { f := func(ctx context.Context, userIDs []string) (result []common_user.CommonUser, err error) {
users, err := fn(ctx, userIDs) users, err := fn(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -85,12 +87,11 @@ func WithRpcFunc(
} }
} }
func NewFriendNotificationSender( func NewFriendNotificationSender(conf *config.Notification, msgClient *rpcli.MsgClient, opts ...friendNotificationSenderOptions) *FriendNotificationSender {
conf *config.Notification,
opts ...friendNotificationSenderOptions,
) *FriendNotificationSender {
f := &FriendNotificationSender{ f := &FriendNotificationSender{
NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient()), NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
return msgClient.SendMsg(ctx, req)
})),
} }
for _, opt := range opts { for _, opt := range opts {
opt(f) opt(f)

@ -19,11 +19,9 @@ import (
"crypto/rand" "crypto/rand"
"time" "time"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/third" "github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
@ -150,7 +148,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
for _, log := range logs { for _, log := range logs {
userIDs = append(userIDs, log.UserID) userIDs = append(userIDs, log.UserID)
} }
userMap, err := rpcclient.GetUsersInfoMap(ctx, userIDs) userMap, err := t.userClient.GetUsersInfoMap(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -19,17 +19,14 @@ import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"path" "path"
"strconv" "strconv"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"go.mongodb.org/mongo-driver/mongo"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/protocol/third" "github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
@ -288,87 +285,35 @@ func (t *thirdServer) apiAddress(prefix, name string) string {
} }
func (t *thirdServer) DeleteOutdatedData(ctx context.Context, req *third.DeleteOutdatedDataReq) (*third.DeleteOutdatedDataResp, error) { func (t *thirdServer) DeleteOutdatedData(ctx context.Context, req *third.DeleteOutdatedDataReq) (*third.DeleteOutdatedDataResp, error) {
var conf config.Third if err := authverify.CheckAdmin(ctx, t.config.Share.IMAdminUserID); err != nil {
expireTime := time.UnixMilli(req.ExpireTime) return nil, err
findPagination := &sdkws.RequestPagination{
PageNumber: 1,
ShowNumber: 500,
} }
engine := t.config.RpcConfig.Object.Enable
expireTime := time.UnixMilli(req.ExpireTime)
// Find all expired data in S3 database // Find all expired data in S3 database
total, models, err := t.s3dataBase.FindNeedDeleteObjectByDB(ctx, expireTime, req.ObjectGroup, findPagination) models, err := t.s3dataBase.FindExpirationObject(ctx, engine, expireTime, req.ObjectGroup, int64(req.Limit))
if err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments { if err != nil {
return nil, errs.Wrap(err) return nil, err
}
if total == 0 {
log.ZDebug(ctx, "Not have OutdatedData", "delete Total", total)
return &third.DeleteOutdatedDataResp{Count: int32(total)}, nil
}
needDelObjectKeys := make([]string, len(models))
for _, model := range models {
needDelObjectKeys = append(needDelObjectKeys, model.Key)
} }
for i, obj := range models {
// Remove duplicate keys, have the same key use in different models if err := t.s3dataBase.DeleteSpecifiedData(ctx, engine, []string{obj.Name}); err != nil {
needDelObjectKeys = datautil.Distinct(needDelObjectKeys)
for _, key := range needDelObjectKeys {
// Find all models by key
keyModels, err := t.s3dataBase.FindModelsByKey(ctx, key)
if err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments {
return nil, errs.Wrap(err) return nil, errs.Wrap(err)
} }
if err := t.s3dataBase.DelS3Key(ctx, engine, obj.Name); err != nil {
// check keyModels, if all keyModels. return nil, err
needDelKey := true // Default can delete
for _, keymodel := range keyModels {
// If group is empty or CreateTime is after expireTime, can't delete this key
if keymodel.Group == "" || keymodel.CreateTime.After(expireTime) {
needDelKey = false
break
}
}
// If this object is not referenced by not expire data, delete it
if needDelKey && t.minio != nil {
// If have a thumbnail, delete it
thumbnailKey, _ := t.getMinioImageThumbnailKey(ctx, key)
if thumbnailKey != "" {
err := t.s3dataBase.DeleteObject(ctx, thumbnailKey)
if err != nil {
log.ZWarn(ctx, "Delete thumbnail object is error:", errs.Wrap(err), "thumbnailKey", thumbnailKey)
}
}
// Delete object
err = t.s3dataBase.DeleteObject(ctx, key)
if err != nil {
log.ZWarn(ctx, "Delete object is error", errs.Wrap(err), "object key", key)
}
// Delete cache key
err = t.s3dataBase.DelS3Key(ctx, conf.Object.Enable, key)
if err != nil {
log.ZWarn(ctx, "Delete cache key is error:", errs.Wrap(err), "cache S3 key:", key)
}
} }
} count, err := t.s3dataBase.GetKeyCount(ctx, engine, obj.Key)
// handle delete data in S3 database
for _, model := range models {
// Delete all expired data row in S3 database
err := t.s3dataBase.DeleteSpecifiedData(ctx, model.Engine, model.Name)
if err != nil { if err != nil {
return nil, errs.Wrap(err) return nil, err
}
log.ZDebug(ctx, "delete s3 object record", "index", i, "s3", obj, "count", count)
if count == 0 {
if err := t.s3.DeleteObject(ctx, obj.Key); err != nil {
return nil, err
}
} }
} }
return &third.DeleteOutdatedDataResp{Count: int32(len(models))}, nil
log.ZDebug(ctx, "DeleteOutdatedData", "delete Total", total)
return &third.DeleteOutdatedDataResp{Count: int32(total)}, nil
} }
type FormDataMate struct { type FormDataMate struct {

@ -17,6 +17,7 @@ package third
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@ -44,7 +45,8 @@ type thirdServer struct {
s3dataBase controller.S3Database s3dataBase controller.S3Database
defaultExpire time.Duration defaultExpire time.Duration
config *Config config *Config
minio *minio.Minio s3 s3.Interface
userClient *rpcli.UserClient
} }
type Config struct { type Config struct {
@ -79,13 +81,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
// Select the oss method according to the profile policy // Select the oss method according to the profile policy
enable := config.RpcConfig.Object.Enable enable := config.RpcConfig.Object.Enable
var ( var (
o s3.Interface o s3.Interface
minioCli *minio.Minio
) )
switch enable { switch enable {
case "minio": case "minio":
minioCli, err = minio.NewMinio(ctx, redis.NewMinioCache(rdb), *config.MinioConfig.Build()) o, err = minio.NewMinio(ctx, redis.NewMinioCache(rdb), *config.MinioConfig.Build())
o = minioCli
case "cos": case "cos":
o, err = cos.NewCos(*config.RpcConfig.Object.Cos.Build()) o, err = cos.NewCos(*config.RpcConfig.Object.Cos.Build())
case "oss": case "oss":
@ -100,21 +100,22 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
if err != nil { if err != nil {
return err return err
} }
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return err
}
localcache.InitLocalCache(&config.LocalCacheConfig) localcache.InitLocalCache(&config.LocalCacheConfig)
third.RegisterThirdServer(server, &thirdServer{ third.RegisterThirdServer(server, &thirdServer{
thirdDatabase: controller.NewThirdDatabase(redis.NewThirdCache(rdb), logdb), thirdDatabase: controller.NewThirdDatabase(redis.NewThirdCache(rdb), logdb),
s3dataBase: controller.NewS3Database(rdb, o, s3db), s3dataBase: controller.NewS3Database(rdb, o, s3db),
defaultExpire: time.Hour * 24 * 7, defaultExpire: time.Hour * 24 * 7,
config: config, config: config,
minio: minioCli, s3: o,
userClient: rpcli.NewUserClient(userConn),
}) })
return nil return nil
} }
func (t *thirdServer) getMinioImageThumbnailKey(ctx context.Context, name string) (string, error) {
return t.minio.GetImageThumbnailKey(ctx, name)
}
func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) { func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) {
err = t.thirdDatabase.FcmUpdateToken(ctx, req.Account, int(req.PlatformID), req.FcmToken, req.ExpireTime) err = t.thirdDatabase.FcmUpdateToken(ctx, req.Account, int(req.PlatformID), req.FcmToken, req.ExpireTime)
if err != nil { if err != nil {

@ -16,19 +16,21 @@ package user
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/msg"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/notification/common_user"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/notification"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
) )
type UserNotificationSender struct { type UserNotificationSender struct {
*rpcclient.NotificationSender *rpcclient.NotificationSender
getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) getUsersInfo func(ctx context.Context, userIDs []string) ([]common_user.CommonUser, error)
// db controller // db controller
db controller.UserDatabase db controller.UserDatabase
} }
@ -45,7 +47,7 @@ func WithUserFunc(
fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error), fn func(ctx context.Context, userIDs []string) (users []*relationtb.User, err error),
) userNotificationSenderOptions { ) userNotificationSenderOptions {
return func(u *UserNotificationSender) { return func(u *UserNotificationSender) {
f := func(ctx context.Context, userIDs []string) (result []notification.CommonUser, err error) { f := func(ctx context.Context, userIDs []string) (result []common_user.CommonUser, err error) {
users, err := fn(ctx, userIDs) users, err := fn(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -59,9 +61,11 @@ func WithUserFunc(
} }
} }
func NewUserNotificationSender(config *Config, opts ...userNotificationSenderOptions) *UserNotificationSender { func NewUserNotificationSender(config *Config, msgClient *rpcli.MsgClient, opts ...userNotificationSenderOptions) *UserNotificationSender {
f := &UserNotificationSender{ f := &UserNotificationSender{
NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient()), NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
return msgClient.SendMsg(ctx, req)
})),
} }
for _, opt := range opts { for _, opt := range opts {
opt(f) opt(f)

@ -17,6 +17,7 @@ package user
import ( import (
"context" "context"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"math/rand" "math/rand"
"strings" "strings"
"sync" "sync"
@ -59,6 +60,8 @@ type userServer struct {
RegisterCenter registry.SvcDiscoveryRegistry RegisterCenter registry.SvcDiscoveryRegistry
config *Config config *Config
webhookClient *webhook.Client webhookClient *webhook.Client
groupClient *rpcli.GroupClient
relationClient *rpcli.RelationClient
} }
type Config struct { type Config struct {
@ -91,6 +94,19 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi
if err != nil { if err != nil {
return err return err
} }
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return err
}
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return err
}
friendConn, err := client.GetConn(ctx, config.Discovery.RpcService.Friend)
if err != nil {
return err
}
msgClient := rpcli.NewMsgClient(msgConn)
userCache := redis.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, redis.GetRocksCacheOptions()) userCache := redis.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, redis.GetRocksCacheOptions())
database := controller.NewUserDatabase(userDB, userCache, mgocli.GetTx()) database := controller.NewUserDatabase(userDB, userCache, mgocli.GetTx())
localcache.InitLocalCache(&config.LocalCacheConfig) localcache.InitLocalCache(&config.LocalCacheConfig)
@ -98,10 +114,13 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi
online: redis.NewUserOnline(rdb), online: redis.NewUserOnline(rdb),
db: database, db: database,
RegisterCenter: client, RegisterCenter: client,
friendNotificationSender: relation.NewFriendNotificationSender(&config.NotificationConfig, relation.WithDBFunc(database.FindWithError)), friendNotificationSender: relation.NewFriendNotificationSender(&config.NotificationConfig, msgClient, relation.WithDBFunc(database.FindWithError)),
userNotificationSender: NewUserNotificationSender(config, WithUserFunc(database.FindWithError)), userNotificationSender: NewUserNotificationSender(config, msgClient, WithUserFunc(database.FindWithError)),
config: config, config: config,
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
groupClient: rpcli.NewGroupClient(groupConn),
relationClient: rpcli.NewRelationClient(friendConn),
} }
pbuser.RegisterUserServer(server, u) pbuser.RegisterUserServer(server, u)
return u.db.InitOnce(context.Background(), users) return u.db.InitOnce(context.Background(), users)
@ -633,7 +652,7 @@ func (s *userServer) NotificationUserInfoUpdate(ctx context.Context, userID stri
wg.Add(len(es)) wg.Add(len(es))
go func() { go func() {
defer wg.Done() defer wg.Done()
_, es[0] = group.NotificationUserInfoUpdateCaller.Invoke(ctx, &group.NotificationUserInfoUpdateReq{ _, es[0] = s.groupClient.NotificationUserInfoUpdate(ctx, &group.NotificationUserInfoUpdateReq{
UserID: userID, UserID: userID,
OldUserInfo: oldUserInfo, OldUserInfo: oldUserInfo,
NewUserInfo: newUserInfo, NewUserInfo: newUserInfo,
@ -642,7 +661,7 @@ func (s *userServer) NotificationUserInfoUpdate(ctx context.Context, userID stri
go func() { go func() {
defer wg.Done() defer wg.Done()
_, es[1] = friendpb.NotificationUserInfoUpdateCaller.Invoke(ctx, &friendpb.NotificationUserInfoUpdateReq{ _, es[1] = s.relationClient.NotificationUserInfoUpdate(ctx, &friendpb.NotificationUserInfoUpdateReq{
UserID: userID, UserID: userID,
OldUserInfo: oldUserInfo, OldUserInfo: oldUserInfo,
NewUserInfo: newUserInfo, NewUserInfo: newUserInfo,

@ -2,10 +2,6 @@ package tools
import ( import (
"context" "context"
"fmt"
"os"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discovery"
pbconversation "github.com/openimsdk/protocol/conversation" pbconversation "github.com/openimsdk/protocol/conversation"
@ -60,87 +56,58 @@ func Start(ctx context.Context, config *CronTaskConfig) error {
return err return err
} }
msgClient := msg.NewMsgClient(msgConn) srv := &cronServer{
conversationClient := pbconversation.NewConversationClient(conversationConn) ctx: ctx,
thirdClient := third.NewThirdClient(thirdConn) config: config,
cron: cron.New(),
crontab := cron.New() msgClient: msg.NewMsgClient(msgConn),
conversationClient: pbconversation.NewConversationClient(conversationConn),
// scheduled hard delete outdated Msgs in specific time. thirdClient: third.NewThirdClient(thirdConn),
destructMsgsFunc := func() {
now := time.Now()
deltime := now.Add(-time.Hour * 24 * time.Duration(config.CronTask.RetainChatRecords))
ctx := mcontext.SetOperationID(ctx, fmt.Sprintf("cron_%d_%d", os.Getpid(), deltime.UnixMilli()))
log.ZDebug(ctx, "Destruct chat records", "deltime", deltime, "timestamp", deltime.UnixMilli())
if _, err := msgClient.DestructMsgs(ctx, &msg.DestructMsgsReq{Timestamp: deltime.UnixMilli()}); err != nil {
log.ZError(ctx, "cron destruct chat records failed", err, "deltime", deltime, "cont", time.Since(now))
return
}
log.ZDebug(ctx, "cron destruct chat records success", "deltime", deltime, "cont", time.Since(now))
}
if _, err := crontab.AddFunc(config.CronTask.CronExecuteTime, destructMsgsFunc); err != nil {
return errs.Wrap(err)
} }
// scheduled soft delete outdated Msgs in specific time when user set `is_msg_destruct` feature. if err := srv.registerClearS3(); err != nil {
clearMsgFunc := func() { return err
now := time.Now()
ctx := mcontext.SetOperationID(ctx, fmt.Sprintf("cron_%d_%d", os.Getpid(), now.UnixMilli()))
log.ZDebug(ctx, "clear msg cron start", "now", now)
conversations, err := conversationClient.GetConversationsNeedClearMsg(ctx, &pbconversation.GetConversationsNeedClearMsgReq{})
if err != nil {
log.ZError(ctx, "Get conversation need Destruct msgs failed.", err)
return
}
_, err = msgClient.ClearMsg(ctx, &msg.ClearMsgReq{Conversations: conversations.Conversations})
if err != nil {
log.ZError(ctx, "Clear Msg failed.", err)
return
}
log.ZDebug(ctx, "clear msg cron task completed", "cont", time.Since(now))
}
if _, err := crontab.AddFunc(config.CronTask.CronExecuteTime, clearMsgFunc); err != nil {
return errs.Wrap(err)
} }
if err := srv.registerDeleteMsg(); err != nil {
// scheduled delete outdated file Objects and their datas in specific time. return err
deleteObjectFunc := func() {
now := time.Now()
executeNum := 5
// number of pagination. if need modify, need update value in third.DeleteOutdatedData
pageShowNumber := 500
deleteTime := now.Add(-time.Hour * 24 * time.Duration(config.CronTask.FileExpireTime))
ctx := mcontext.SetOperationID(ctx, fmt.Sprintf("cron_%d_%d", os.Getpid(), deleteTime.UnixMilli()))
log.ZDebug(ctx, "deleteoutDatedData", "deletetime", deleteTime, "timestamp", deleteTime.UnixMilli())
if len(config.CronTask.DeleteObjectType) == 0 {
log.ZDebug(ctx, "cron deleteoutDatedData not type need delete", "deletetime", deleteTime, "DeleteObjectType", config.CronTask.DeleteObjectType, "cont", time.Since(now))
return
}
for i := 0; i < executeNum; i++ {
resp, err := thirdClient.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{ExpireTime: deleteTime.UnixMilli(), ObjectGroup: config.CronTask.DeleteObjectType})
if err != nil {
log.ZError(ctx, "cron deleteoutDatedData failed", err, "deleteTime", deleteTime, "cont", time.Since(now))
return
}
if resp.Count == 0 || resp.Count < int32(pageShowNumber) {
break
}
}
log.ZDebug(ctx, "cron deleteoutDatedData success", "deltime", deleteTime, "cont", time.Since(now))
} }
if _, err := crontab.AddFunc(config.CronTask.CronExecuteTime, deleteObjectFunc); err != nil { if err := srv.registerClearUserMsg(); err != nil {
return errs.Wrap(err) return err
} }
log.ZDebug(ctx, "start cron task", "CronExecuteTime", config.CronTask.CronExecuteTime) log.ZDebug(ctx, "start cron task", "CronExecuteTime", config.CronTask.CronExecuteTime)
crontab.Start() srv.cron.Start()
<-ctx.Done() <-ctx.Done()
return nil return nil
} }
type cronServer struct {
ctx context.Context
config *CronTaskConfig
cron *cron.Cron
msgClient msg.MsgClient
conversationClient pbconversation.ConversationClient
thirdClient third.ThirdClient
}
func (c *cronServer) registerClearS3() error {
if c.config.CronTask.FileExpireTime <= 0 || len(c.config.CronTask.DeleteObjectType) == 0 {
log.ZInfo(c.ctx, "disable scheduled cleanup of s3", "fileExpireTime", c.config.CronTask.FileExpireTime, "deleteObjectType", c.config.CronTask.DeleteObjectType)
return nil
}
_, err := c.cron.AddFunc(c.config.CronTask.CronExecuteTime, c.clearS3)
return errs.WrapMsg(err, "failed to register clear s3 cron task")
}
func (c *cronServer) registerDeleteMsg() error {
if c.config.CronTask.RetainChatRecords <= 0 {
log.ZInfo(c.ctx, "disable scheduled cleanup of chat records", "retainChatRecords", c.config.CronTask.RetainChatRecords)
return nil
}
_, err := c.cron.AddFunc(c.config.CronTask.CronExecuteTime, c.deleteMsg)
return errs.WrapMsg(err, "failed to register delete msg cron task")
}
func (c *cronServer) registerClearUserMsg() error {
_, err := c.cron.AddFunc(c.config.CronTask.CronExecuteTime, c.clearUserMsg)
return errs.WrapMsg(err, "failed to register clear user msg cron task")
}

@ -0,0 +1,63 @@
package tools
import (
"context"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
pbconversation "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/mcontext"
"github.com/openimsdk/tools/mw"
"github.com/robfig/cron/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"testing"
)
func TestName(t *testing.T) {
conf := &config.Discovery{
Enable: config.ETCD,
Etcd: config.Etcd{
RootDirectory: "openim",
Address: []string{"localhost:12379"},
},
}
client, err := kdisc.NewDiscoveryRegister(conf, "source")
if err != nil {
panic(err)
}
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
ctx := mcontext.SetOpUserID(context.Background(), "imAdmin")
msgConn, err := client.GetConn(ctx, "msg-rpc-service")
if err != nil {
panic(err)
}
thirdConn, err := client.GetConn(ctx, "third-rpc-service")
if err != nil {
panic(err)
}
conversationConn, err := client.GetConn(ctx, "conversation-rpc-service")
if err != nil {
panic(err)
}
srv := &cronServer{
ctx: ctx,
config: &CronTaskConfig{
CronTask: config.CronTask{
RetainChatRecords: 1,
FileExpireTime: 1,
DeleteObjectType: []string{"msg-picture", "msg-file", "msg-voice", "msg-video", "msg-video-snapshot", "sdklog", ""},
},
},
cron: cron.New(),
msgClient: msg.NewMsgClient(msgConn),
conversationClient: pbconversation.NewConversationClient(conversationConn),
thirdClient: third.NewThirdClient(thirdConn),
}
srv.deleteMsg()
//srv.clearS3()
//srv.clearUserMsg()
}

@ -0,0 +1,36 @@
package tools
import (
"fmt"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext"
"os"
"time"
)
func (c *cronServer) deleteMsg() {
now := time.Now()
deltime := now.Add(-time.Hour * 24 * time.Duration(c.config.CronTask.RetainChatRecords))
operationID := fmt.Sprintf("cron_msg_%d_%d", os.Getpid(), deltime.UnixMilli())
ctx := mcontext.SetOperationID(c.ctx, operationID)
log.ZDebug(ctx, "Destruct chat records", "deltime", deltime, "timestamp", deltime.UnixMilli())
const (
deleteCount = 10000
deleteLimit = 50
)
var count int
for i := 1; i <= deleteCount; i++ {
ctx := mcontext.SetOperationID(c.ctx, fmt.Sprintf("%s_%d", operationID, i))
resp, err := c.msgClient.DestructMsgs(ctx, &msg.DestructMsgsReq{Timestamp: deltime.UnixMilli(), Limit: deleteLimit})
if err != nil {
log.ZError(ctx, "cron destruct chat records failed", err)
break
}
count += int(resp.Count)
if resp.Count < deleteLimit {
break
}
}
log.ZDebug(ctx, "cron destruct chat records end", "deltime", deltime, "cont", time.Since(now), "count", count)
}

@ -0,0 +1,79 @@
package tools
import (
"fmt"
"github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext"
"os"
"time"
)
func (c *cronServer) clearS3() {
start := time.Now()
deleteTime := start.Add(-time.Hour * 24 * time.Duration(c.config.CronTask.FileExpireTime))
operationID := fmt.Sprintf("cron_s3_%d_%d", os.Getpid(), deleteTime.UnixMilli())
ctx := mcontext.SetOperationID(c.ctx, operationID)
log.ZDebug(ctx, "deleteoutDatedData", "deletetime", deleteTime, "timestamp", deleteTime.UnixMilli())
const (
deleteCount = 10000
deleteLimit = 100
)
var count int
for i := 1; i <= deleteCount; i++ {
resp, err := c.thirdClient.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{ExpireTime: deleteTime.UnixMilli(), ObjectGroup: c.config.CronTask.DeleteObjectType, Limit: deleteLimit})
if err != nil {
log.ZError(ctx, "cron deleteoutDatedData failed", err)
return
}
count += int(resp.Count)
if resp.Count < deleteLimit {
break
}
}
log.ZDebug(ctx, "cron deleteoutDatedData success", "deltime", deleteTime, "cont", time.Since(start), "count", count)
}
// var req *third.DeleteOutdatedDataReq
// count1, err := ExtractField(ctx, c.thirdClient.DeleteOutdatedData, req, (*third.DeleteOutdatedDataResp).GetCount)
//
// c.thirdClient.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{})
// msggateway.GetUsersOnlineStatusCaller.Invoke(ctx, &msggateway.GetUsersOnlineStatusReq{})
//
// var cli ThirdClient
//
// c111, err := cli.DeleteOutdatedData(ctx, 100)
//
// cli.ThirdClient.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{})
//
// cli.AuthSign(ctx, &third.AuthSignReq{})
//
// cli.SetAppBadge()
//
//}
//
//func extractField[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
// resp, err := fn(ctx, req)
// if err != nil {
// var c C
// return c, err
// }
// return get(resp), nil
//}
//
//func ignore(_ any, err error) error {
// return err
//}
//
//type ThirdClient struct {
// third.ThirdClient
//}
//
//func (c *ThirdClient) DeleteOutdatedData(ctx context.Context, expireTime int64) (int32, error) {
// return extractField(ctx, c.ThirdClient.DeleteOutdatedData, &third.DeleteOutdatedDataReq{ExpireTime: expireTime}, (*third.DeleteOutdatedDataResp).GetCount)
//}
//
//func (c *ThirdClient) DeleteOutdatedData1(ctx context.Context, expireTime int64) error {
// return ignore(c.ThirdClient.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{ExpireTime: expireTime}))
//}

@ -0,0 +1,34 @@
package tools
import (
"fmt"
pbconversation "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext"
"os"
"time"
)
func (c *cronServer) clearUserMsg() {
now := time.Now()
operationID := fmt.Sprintf("cron_user_msg_%d_%d", os.Getpid(), now.UnixMilli())
ctx := mcontext.SetOperationID(c.ctx, operationID)
log.ZDebug(ctx, "clear user msg cron start")
const (
deleteCount = 10000
deleteLimit = 100
)
var count int
for i := 1; i <= deleteCount; i++ {
resp, err := c.conversationClient.ClearUserConversationMsg(ctx, &pbconversation.ClearUserConversationMsgReq{Timestamp: now.UnixMilli(), Limit: deleteLimit})
if err != nil {
log.ZError(ctx, "ClearUserConversationMsg failed.", err)
return
}
count += int(resp.Count)
if resp.Count < deleteLimit {
break
}
}
log.ZDebug(ctx, "clear user msg cron task completed", "cont", time.Since(now), "count", count)
}

@ -80,9 +80,18 @@ func Db2PbGroupMember(m *model.GroupMember) *sdkws.GroupMemberFullInfo {
} }
} }
func Db2PbGroupRequest(m *model.GroupRequest, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest { func Db2PbGroupRequest(m *model.GroupRequest, user *sdkws.UserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest {
var pu *sdkws.PublicUserInfo
if user != nil {
pu = &sdkws.PublicUserInfo{
UserID: user.UserID,
Nickname: user.Nickname,
FaceURL: user.FaceURL,
Ex: user.Ex,
}
}
return &sdkws.GroupRequest{ return &sdkws.GroupRequest{
UserInfo: user, UserInfo: pu,
GroupInfo: group, GroupInfo: group,
HandleResult: m.HandleResult, HandleResult: m.HandleResult,
ReqMsg: m.ReqMsg, ReqMsg: m.ReqMsg,

@ -28,7 +28,6 @@ import (
conf "github.com/openimsdk/open-im-server/v3/pkg/common/config" conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd" disetcd "github.com/openimsdk/open-im-server/v3/pkg/common/discovery/etcd"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/jsonutil" "github.com/openimsdk/tools/utils/jsonutil"
@ -103,10 +102,6 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
defer client.Close() defer client.Close()
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
if err = rpcclient.InitRpcCaller(client, discovery.RpcService); err != nil {
return err
}
// var reg *prometheus.Registry // var reg *prometheus.Registry
// var metric *grpcprometheus.ServerMetrics // var metric *grpcprometheus.ServerMetrics
if prometheusConfig.Enable { if prometheusConfig.Enable {

@ -74,6 +74,8 @@ type ConversationDatabase interface {
GetNotNotifyConversationIDs(ctx context.Context, userID string) ([]string, error) GetNotNotifyConversationIDs(ctx context.Context, userID string) ([]string, error)
// GetPinnedConversationIDs gets pinned conversationIDs by userID // GetPinnedConversationIDs gets pinned conversationIDs by userID
GetPinnedConversationIDs(ctx context.Context, userID string) ([]string, error) GetPinnedConversationIDs(ctx context.Context, userID string) ([]string, error)
// FindRandConversation finds random conversations based on the specified timestamp and limit.
FindRandConversation(ctx context.Context, ts int64, limit int) ([]*relationtb.Conversation, error)
} }
func NewConversationDatabase(conversation database.Conversation, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase { func NewConversationDatabase(conversation database.Conversation, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase {
@ -401,3 +403,7 @@ func (c *conversationDatabase) GetPinnedConversationIDs(ctx context.Context, use
} }
return conversationIDs, nil return conversationIDs, nil
} }
func (c *conversationDatabase) FindRandConversation(ctx context.Context, ts int64, limit int) ([]*relationtb.Conversation, error) {
return c.conversationDB.FindRandConversation(ctx, ts, limit)
}

@ -18,7 +18,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
@ -69,6 +68,7 @@ type CommonMsgDatabase interface {
GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error)
GetMaxSeq(ctx context.Context, conversationID string) (int64, error) GetMaxSeq(ctx context.Context, conversationID string) (int64, error)
SetMinSeqs(ctx context.Context, seqs map[string]int64) error SetMinSeqs(ctx context.Context, seqs map[string]int64) error
SetMinSeq(ctx context.Context, conversationID string, seq int64) error
SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error)
SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error
@ -95,13 +95,16 @@ type CommonMsgDatabase interface {
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
// get Msg when destruct msg before // get Msg when destruct msg before
GetBeforeMsg(ctx context.Context, ts int64, docIds []string, limit int) ([]*model.MsgDocModel, error) //DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error)
DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error)
GetDocIDs(ctx context.Context) ([]string, error) GetRandBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error)
SetUserConversationsMaxSeq(ctx context.Context, conversationID string, userID string, seq int64) error SetUserConversationsMaxSeq(ctx context.Context, conversationID string, userID string, seq int64) error
SetUserConversationsMinSeq(ctx context.Context, conversationID string, userID string, seq int64) error SetUserConversationsMinSeq(ctx context.Context, conversationID string, userID string, seq int64) error
DeleteDoc(ctx context.Context, docID string) error
GetLastMessageSeqByTime(ctx context.Context, conversationID string, time int64) (int64, error)
} }
func NewCommonMsgDatabase(msgDocModel database.Msg, msg cache.MsgCache, seqUser cache.SeqUser, seqConversation cache.SeqConversationCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) { func NewCommonMsgDatabase(msgDocModel database.Msg, msg cache.MsgCache, seqUser cache.SeqUser, seqConversation cache.SeqConversationCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) {
@ -806,9 +809,10 @@ func (db *commonMsgDatabase) GetMaxSeq(ctx context.Context, conversationID strin
return db.seqConversation.GetMaxSeq(ctx, conversationID) return db.seqConversation.GetMaxSeq(ctx, conversationID)
} }
func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error { //
return db.seqConversation.SetMinSeq(ctx, conversationID, minSeq) //func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
} // return db.seqConversation.SetMinSeq(ctx, conversationID, minSeq)
//}
func (db *commonMsgDatabase) SetMinSeqs(ctx context.Context, seqs map[string]int64) error { func (db *commonMsgDatabase) SetMinSeqs(ctx context.Context, seqs map[string]int64) error {
return db.seqConversation.SetMinSeqs(ctx, seqs) return db.seqConversation.SetMinSeqs(ctx, seqs)
@ -947,56 +951,40 @@ func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversation
db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs) db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
} }
func (db *commonMsgDatabase) GetBeforeMsg(ctx context.Context, ts int64, docIDs []string, limit int) ([]*model.MsgDocModel, error) { func (db *commonMsgDatabase) GetRandBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) {
var msgs []*model.MsgDocModel return db.msgDocDatabase.GetRandBeforeMsg(ctx, ts, limit)
for i := 0; i < len(docIDs); i += 1000 {
end := i + 1000
if end > len(docIDs) {
end = len(docIDs)
}
res, err := db.msgDocDatabase.GetBeforeMsg(ctx, ts, docIDs[i:end], limit)
if err != nil {
return nil, err
}
msgs = append(msgs, res...)
if len(msgs) >= limit {
return msgs[:limit], nil
}
}
return msgs, nil
} }
func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error) { //
var notNull int //func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *model.MsgDocModel) ([]int, error) {
index := make([]int, 0, len(doc.Msg)) // var notNull int
for i, message := range doc.Msg { // index := make([]int, 0, len(doc.Msg))
if message.Msg != nil { // for i, message := range doc.Msg {
notNull++ // if message.Msg != nil {
if message.Msg.SendTime < ts { // notNull++
index = append(index, i) // if message.Msg.SendTime < ts {
} // index = append(index, i)
} // }
} // }
if len(index) == 0 { // }
return index, nil // if len(index) == 0 {
} // return index, nil
maxSeq := doc.Msg[index[len(index)-1]].Msg.Seq // }
conversationID := doc.DocID[:strings.LastIndex(doc.DocID, ":")] // maxSeq := doc.Msg[index[len(index)-1]].Msg.Seq
if err := db.setMinSeq(ctx, conversationID, maxSeq+1); err != nil { // conversationID := doc.DocID[:strings.LastIndex(doc.DocID, ":")]
return index, err // if err := db.SetMinSeq(ctx, conversationID, maxSeq+1); err != nil {
} // return index, err
if len(index) == notNull { // }
log.ZDebug(ctx, "Delete db in Doc", "DocID", doc.DocID, "index", index, "maxSeq", maxSeq) // if len(index) == notNull {
return index, db.msgDocDatabase.DeleteDoc(ctx, doc.DocID) // log.ZDebug(ctx, "Delete db in Doc", "DocID", doc.DocID, "index", index, "maxSeq", maxSeq)
} else { // return index, db.msgDocDatabase.DeleteDoc(ctx, doc.DocID)
log.ZDebug(ctx, "delete db in index", "DocID", doc.DocID, "index", index, "maxSeq", maxSeq) // } else {
return index, db.msgDocDatabase.DeleteMsgByIndex(ctx, doc.DocID, index) // log.ZDebug(ctx, "delete db in index", "DocID", doc.DocID, "index", index, "maxSeq", maxSeq)
} // return index, db.msgDocDatabase.DeleteMsgByIndex(ctx, doc.DocID, index)
} // }
//}
func (db *commonMsgDatabase) setMinSeq(ctx context.Context, conversationID string, seq int64) error {
func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, seq int64) error {
dbSeq, err := db.seqConversation.GetMinSeq(ctx, conversationID) dbSeq, err := db.seqConversation.GetMinSeq(ctx, conversationID)
if err != nil { if err != nil {
if errors.Is(errs.Unwrap(err), redis.Nil) { if errors.Is(errs.Unwrap(err), redis.Nil) {
@ -1010,8 +998,8 @@ func (db *commonMsgDatabase) setMinSeq(ctx context.Context, conversationID strin
return db.seqConversation.SetMinSeq(ctx, conversationID, seq) return db.seqConversation.SetMinSeq(ctx, conversationID, seq)
} }
func (db *commonMsgDatabase) GetDocIDs(ctx context.Context) ([]string, error) { func (db *commonMsgDatabase) GetRandDocIDs(ctx context.Context, limit int) ([]string, error) {
return db.msgDocDatabase.GetDocIDs(ctx) return db.msgDocDatabase.GetRandDocIDs(ctx, limit)
} }
func (db *commonMsgDatabase) GetCacheMaxSeqWithTime(ctx context.Context, conversationIDs []string) (map[string]database.SeqTime, error) { func (db *commonMsgDatabase) GetCacheMaxSeqWithTime(ctx context.Context, conversationIDs []string) (map[string]database.SeqTime, error) {
@ -1026,3 +1014,11 @@ func (db *commonMsgDatabase) GetMaxSeqsWithTime(ctx context.Context, conversatio
// todo: only the time in the redis cache will be taken, not the message time // todo: only the time in the redis cache will be taken, not the message time
return db.seqConversation.GetMaxSeqsWithTime(ctx, conversationIDs) return db.seqConversation.GetMaxSeqsWithTime(ctx, conversationIDs)
} }
func (db *commonMsgDatabase) DeleteDoc(ctx context.Context, docID string) error {
return db.msgDocDatabase.DeleteDoc(ctx, docID)
}
func (db *commonMsgDatabase) GetLastMessageSeqByTime(ctx context.Context, conversationID string, time int64) (int64, error) {
return db.msgDocDatabase.GetLastMessageSeqByTime(ctx, conversationID, time)
}

@ -24,7 +24,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache"
"github.com/openimsdk/tools/db/pagination"
"github.com/openimsdk/tools/s3" "github.com/openimsdk/tools/s3"
"github.com/openimsdk/tools/s3/cont" "github.com/openimsdk/tools/s3/cont"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
@ -40,11 +39,10 @@ type S3Database interface {
SetObject(ctx context.Context, info *model.Object) error SetObject(ctx context.Context, info *model.Object) error
StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error)
FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error)
FindNeedDeleteObjectByDB(ctx context.Context, duration time.Time, needDelType []string, pagination pagination.Pagination) (total int64, objects []*model.Object, err error) FindExpirationObject(ctx context.Context, engine string, expiration time.Time, needDelType []string, count int64) ([]*model.Object, error)
DeleteObject(ctx context.Context, name string) error DeleteSpecifiedData(ctx context.Context, engine string, name []string) error
DeleteSpecifiedData(ctx context.Context, engine string, name string) error
FindModelsByKey(ctx context.Context, key string) (objects []*model.Object, err error)
DelS3Key(ctx context.Context, engine string, keys ...string) error DelS3Key(ctx context.Context, engine string, keys ...string) error
GetKeyCount(ctx context.Context, engine string, key string) (int64, error)
} }
func NewS3Database(rdb redis.UniversalClient, s3 s3.Interface, obj database.ObjectInfo) S3Database { func NewS3Database(rdb redis.UniversalClient, s3 s3.Interface, obj database.ObjectInfo) S3Database {
@ -120,19 +118,17 @@ func (s *s3Database) StatObject(ctx context.Context, name string) (*s3.ObjectInf
func (s *s3Database) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { func (s *s3Database) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) {
return s.s3.FormData(ctx, name, size, contentType, duration) return s.s3.FormData(ctx, name, size, contentType, duration)
} }
func (s *s3Database) FindNeedDeleteObjectByDB(ctx context.Context, duration time.Time, needDelType []string, pagination pagination.Pagination) (total int64, objects []*model.Object, err error) {
return s.db.FindNeedDeleteObjectByDB(ctx, duration, needDelType, pagination)
}
func (s *s3Database) DeleteObject(ctx context.Context, name string) error { func (s *s3Database) FindExpirationObject(ctx context.Context, engine string, expiration time.Time, needDelType []string, count int64) ([]*model.Object, error) {
return s.s3.DeleteObject(ctx, name) return s.db.FindExpirationObject(ctx, engine, expiration, needDelType, count)
} }
func (s *s3Database) DeleteSpecifiedData(ctx context.Context, engine string, name string) error {
return s.db.Delete(ctx, engine, name) func (s *s3Database) GetKeyCount(ctx context.Context, engine string, key string) (int64, error) {
return s.db.GetKeyCount(ctx, engine, key)
} }
func (s *s3Database) FindModelsByKey(ctx context.Context, key string) (objects []*model.Object, err error) { func (s *s3Database) DeleteSpecifiedData(ctx context.Context, engine string, name []string) error {
return s.db.FindModelsByKey(ctx, key) return s.db.Delete(ctx, engine, name)
} }
func (s *s3Database) DelS3Key(ctx context.Context, engine string, keys ...string) error { func (s *s3Database) DelS3Key(ctx context.Context, engine string, keys ...string) error {

@ -42,4 +42,5 @@ type Conversation interface {
GetConversationIDsNeedDestruct(ctx context.Context) ([]*model.Conversation, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*model.Conversation, error)
GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error)
FindConversationUserVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) FindConversationUserVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error)
FindRandConversation(ctx context.Context, ts int64, limit int) ([]*model.Conversation, error)
} }

@ -228,3 +228,35 @@ func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Co
func (c *ConversationMgo) FindConversationUserVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) { func (c *ConversationMgo) FindConversationUserVersion(ctx context.Context, userID string, version uint, limit int) (*model.VersionLog, error) {
return c.version.FindChangeLog(ctx, userID, version, limit) return c.version.FindChangeLog(ctx, userID, version, limit)
} }
func (c *ConversationMgo) FindRandConversation(ctx context.Context, ts int64, limit int) ([]*model.Conversation, error) {
pipeline := []bson.M{
{
"$match": bson.M{
"is_msg_destruct": true,
"msg_destruct_time": bson.M{"$ne": 0},
},
},
{
"$addFields": bson.M{
"next_msg_destruct_timestamp": bson.M{
"$add": []any{
bson.M{
"$toLong": "$latest_msg_destruct_time",
}, "$msg_destruct_time"},
},
},
},
{
"$match": bson.M{
"next_msg_destruct_timestamp": bson.M{"$lt": ts},
},
},
{
"$sample": bson.M{
"size": limit,
},
},
}
return mongoutil.Aggregate[*model.Conversation](ctx, c.coll, pipeline)
}

@ -1227,8 +1227,7 @@ func (m *MsgMgo) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string
} }
} }
func (m *MsgMgo) GetDocIDs(ctx context.Context) ([]string, error) { func (m *MsgMgo) GetRandDocIDs(ctx context.Context, limit int) ([]string, error) {
limit := 5000
var skip int var skip int
var docIDs []string var docIDs []string
var offset int var offset int
@ -1267,15 +1266,18 @@ func (m *MsgMgo) GetDocIDs(ctx context.Context) ([]string, error) {
return docIDs, errs.Wrap(err) return docIDs, errs.Wrap(err)
} }
func (m *MsgMgo) GetBeforeMsg(ctx context.Context, ts int64, docIDs []string, limit int) ([]*model.MsgDocModel, error) { func (m *MsgMgo) GetRandBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error) {
return mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, []bson.M{ return mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, []bson.M{
{ {
"$match": bson.M{ "$match": bson.M{
"doc_id": bson.M{ "msgs": bson.M{
"$in": docIDs, "$not": bson.M{
}, "$elemMatch": bson.M{
"msgs.msg.send_time": bson.M{ "msg.send_time": bson.M{
"$lt": ts, "$gt": ts,
},
},
},
}, },
}, },
}, },
@ -1288,7 +1290,9 @@ func (m *MsgMgo) GetBeforeMsg(ctx context.Context, ts int64, docIDs []string, li
}, },
}, },
{ {
"$limit": limit, "$sample": bson.M{
"size": limit,
},
}, },
}) })
} }
@ -1305,53 +1309,58 @@ func (m *MsgMgo) DeleteMsgByIndex(ctx context.Context, docID string, index []int
return mongoutil.UpdateOne(ctx, m.coll, bson.M{"doc_id": docID}, bson.M{"$set": set}, true) return mongoutil.UpdateOne(ctx, m.coll, bson.M{"doc_id": docID}, bson.M{"$set": set}, true)
} }
//func (m *MsgMgo) ClearMsg(ctx context.Context, t time.Time) (int64, error) {
// ts := t.UnixMilli()
// var count int64
// for {
// msgs, err := m.GetBeforeMsg(ctx, ts, 100)
// if err != nil {
// return count, err
// }
// if len(msgs) == 0 {
// return count, nil
// }
// for _, msg := range msgs {
// num, err := m.deleteOneMsg(ctx, ts, msg)
// count += num
// if err != nil {
// return count, err
// }
// }
// }
//}
func (m *MsgMgo) DeleteDoc(ctx context.Context, docID string) error { func (m *MsgMgo) DeleteDoc(ctx context.Context, docID string) error {
return mongoutil.DeleteOne(ctx, m.coll, bson.M{"doc_id": docID}) return mongoutil.DeleteOne(ctx, m.coll, bson.M{"doc_id": docID})
} }
//func (m *MsgMgo) DeleteDocMsg(ctx context.Context, ts int64, doc *relation.MsgDocModel) (int64, error) { func (m *MsgMgo) GetLastMessageSeqByTime(ctx context.Context, conversationID string, time int64) (int64, error) {
// var notNull int pipeline := []bson.M{
// index := make([]int, 0, len(doc.Msg)) {
// for i, message := range doc.Msg { "$match": bson.M{
// if message.Msg != nil { "doc_id": bson.M{
// notNull++ "$regex": fmt.Sprintf("^%s", conversationID),
// if message.Msg.SendTime < ts { },
// index = append(index, i) },
// } },
// } {
// } "$match": bson.M{
// if len(index) == 0 { "msgs.msg.send_time": bson.M{
// return 0, errs.New("no msg to delete").WrapMsg("deleteOneMsg", "docID", doc.DocID) "$lte": time,
// } },
// if len(index) == notNull { },
// if err := m.DeleteDoc(ctx, doc.DocID); err != nil { },
// return 0, err {
// } "$sort": bson.M{
// } else { "_id": -1,
// if err := m.setNullMsg(ctx, doc.DocID, index); err != nil { },
// return 0, err },
// } {
// } "$limit": 1,
// return int64(len(index)), nil },
//} {
"$project": bson.M{
"_id": 0,
"doc_id": 1,
"msgs.msg.send_time": 1,
"msgs.msg.seq": 1,
},
},
}
res, err := mongoutil.Aggregate[*model.MsgDocModel](ctx, m.coll, pipeline)
if err != nil {
return 0, err
}
if len(res) == 0 {
return 0, nil
}
var seq int64
for _, v := range res[0].Msg {
if v.Msg == nil {
continue
}
if v.Msg.SendTime <= time {
seq = v.Msg.Seq
}
}
return seq, nil
}

@ -3,12 +3,11 @@ package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/mongoutil"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"math"
"math/rand" "math/rand"
"strconv" "strconv"
"testing" "testing"
@ -16,35 +15,45 @@ import (
) )
func TestName1(t *testing.T) { func TestName1(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*300) //ctx, cancel := context.WithTimeout(context.Background(), time.Second*300)
defer cancel() //defer cancel()
cli := Result(mongo.Connect(ctx, options.Client().ApplyURI("mongodb://openIM:openIM123@172.16.8.48:37017/openim_v3?maxPoolSize=100").SetConnectTimeout(5*time.Second))) //cli := Result(mongo.Connect(ctx, options.Client().ApplyURI("mongodb://openIM:openIM123@172.16.8.66:37017/openim_v3?maxPoolSize=100").SetConnectTimeout(5*time.Second)))
//
v := &MsgMgo{ //v := &MsgMgo{
coll: cli.Database("openim_v3").Collection("msg3"), // coll: cli.Database("openim_v3").Collection("msg3"),
} //}
//
req := &msg.SearchMessageReq{ //req := &msg.SearchMessageReq{
//RecvID: "3187706596", // //RecvID: "3187706596",
//SendID: "7009965934", // //SendID: "7009965934",
ContentType: 101, // ContentType: 101,
//SendTime: "2024-05-06", // //SendTime: "2024-05-06",
//SessionType: 3, // //SessionType: 3,
Pagination: &sdkws.RequestPagination{ // Pagination: &sdkws.RequestPagination{
PageNumber: 1, // PageNumber: 1,
ShowNumber: 10, // ShowNumber: 10,
}, // },
} //}
total, res, err := v.SearchMessage(ctx, req) //total, res, err := v.SearchMessage(ctx, req)
if err != nil { //if err != nil {
panic(err) // panic(err)
} //}
//
for i, re := range res { //for i, re := range res {
t.Logf("%d => %d | %+v", i+1, re.Msg.Seq, re.Msg.Content) // t.Logf("%d => %d | %+v", i+1, re.Msg.Seq, re.Msg.Content)
} //}
//
t.Log(total) //t.Log(total)
//
//msg, err := NewMsgMongo(cli.Database("openim_v3"))
//if err != nil {
// panic(err)
//}
//res, err := msg.GetBeforeMsg(ctx, time.Now().UnixMilli(), []string{"1:0"}, 1000)
//if err != nil {
// panic(err)
//}
//t.Log(len(res))
} }
func TestName10(t *testing.T) { func TestName10(t *testing.T) {
@ -73,3 +82,33 @@ func TestName10(t *testing.T) {
} }
} }
func TestName3(t *testing.T) {
t.Log(uint64(math.MaxUint64))
t.Log(int64(math.MaxInt64))
t.Log(int64(math.MinInt64))
}
func TestName4(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*300)
defer cancel()
cli := Result(mongo.Connect(ctx, options.Client().ApplyURI("mongodb://openIM:openIM123@172.16.8.66:37017/openim_v3?maxPoolSize=100").SetConnectTimeout(5*time.Second)))
msg, err := NewMsgMongo(cli.Database("openim_v3"))
if err != nil {
panic(err)
}
ts := time.Now().Add(-time.Hour * 24 * 5).UnixMilli()
t.Log(ts)
res, err := msg.GetLastMessageSeqByTime(ctx, "sg_1523453548", ts)
if err != nil {
panic(err)
}
t.Log(res)
}
func TestName5(t *testing.T) {
var v time.Time
t.Log(v.UnixMilli())
}

@ -22,7 +22,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/mongoutil"
"github.com/openimsdk/tools/db/pagination"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
@ -91,21 +90,25 @@ func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*model.
return mongoutil.FindOne[*model.Object](ctx, o.coll, bson.M{"name": name, "engine": engine}) return mongoutil.FindOne[*model.Object](ctx, o.coll, bson.M{"name": name, "engine": engine})
} }
func (o *S3Mongo) Delete(ctx context.Context, engine string, name string) error { func (o *S3Mongo) Delete(ctx context.Context, engine string, name []string) error {
return mongoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) if len(name) == 0 {
return nil
}
return mongoutil.DeleteOne(ctx, o.coll, bson.M{"engine": engine, "name": bson.M{"$in": name}})
} }
// Find Expires object func (o *S3Mongo) FindExpirationObject(ctx context.Context, engine string, expiration time.Time, needDelType []string, count int64) ([]*model.Object, error) {
func (o *S3Mongo) FindNeedDeleteObjectByDB(ctx context.Context, duration time.Time, needDelType []string, pagination pagination.Pagination) (total int64, objects []*model.Object, err error) { opt := options.Find()
return mongoutil.FindPage[*model.Object](ctx, o.coll, bson.M{ if count > 0 {
"create_time": bson.M{"$lt": duration}, opt.SetLimit(count)
}
return mongoutil.Find[*model.Object](ctx, o.coll, bson.M{
"engine": engine,
"create_time": bson.M{"$lt": expiration},
"group": bson.M{"$in": needDelType}, "group": bson.M{"$in": needDelType},
}, pagination) }, opt)
} }
// Find object by key func (o *S3Mongo) GetKeyCount(ctx context.Context, engine string, key string) (int64, error) {
func (o *S3Mongo) FindModelsByKey(ctx context.Context, key string) (objects []*model.Object, err error) { return mongoutil.Count(ctx, o.coll, bson.M{"engine": engine, "key": key})
return mongoutil.Find[*model.Object](ctx, o.coll, bson.M{
"key": key,
})
} }

@ -45,7 +45,9 @@ type Msg interface {
DeleteDoc(ctx context.Context, docID string) error DeleteDoc(ctx context.Context, docID string) error
DeleteMsgByIndex(ctx context.Context, docID string, index []int) error DeleteMsgByIndex(ctx context.Context, docID string, index []int) error
GetBeforeMsg(ctx context.Context, ts int64, docIDs []string, limit int) ([]*model.MsgDocModel, error) GetRandBeforeMsg(ctx context.Context, ts int64, limit int) ([]*model.MsgDocModel, error)
GetDocIDs(ctx context.Context) ([]string, error) GetRandDocIDs(ctx context.Context, limit int) ([]string, error)
GetLastMessageSeqByTime(ctx context.Context, conversationID string, time int64) (int64, error)
} }

@ -19,13 +19,12 @@ import (
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/tools/db/pagination"
) )
type ObjectInfo interface { type ObjectInfo interface {
SetObject(ctx context.Context, obj *model.Object) error SetObject(ctx context.Context, obj *model.Object) error
Take(ctx context.Context, engine string, name string) (*model.Object, error) Take(ctx context.Context, engine string, name string) (*model.Object, error)
Delete(ctx context.Context, engine string, name string) error Delete(ctx context.Context, engine string, name []string) error
FindNeedDeleteObjectByDB(ctx context.Context, duration time.Time, needDelType []string, pagination pagination.Pagination) (total int64, objects []*model.Object, err error) FindExpirationObject(ctx context.Context, engine string, expiration time.Time, needDelType []string, count int64) ([]*model.Object, error)
FindModelsByKey(ctx context.Context, key string) (objects []*model.Object, err error) GetKeyCount(ctx context.Context, engine string, key string) (int64, error)
} }

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package notification package common_user
type CommonUser interface { type CommonUser interface {
GetNickname() string GetNickname() string

@ -148,17 +148,17 @@ func WithLocalSendMsg(sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*m
} }
} }
func WithRpcClient() NotificationSenderOptions { func WithRpcClient(sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error)) NotificationSenderOptions {
return func(s *NotificationSender) { return func(s *NotificationSender) {
s.sendMsg = func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) { s.sendMsg = func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
return msg.SendMsgCaller.Invoke(ctx, req) return sendMsg(ctx, req)
} }
} }
} }
func WithUserRpcClient() NotificationSenderOptions { func WithUserRpcClient(getUserInfo func(ctx context.Context, userID string) (*sdkws.UserInfo, error)) NotificationSenderOptions {
return func(s *NotificationSender) { return func(s *NotificationSender) {
s.getUserInfo = GetUserInfo s.getUserInfo = getUserInfo
} }
} }

@ -16,12 +16,11 @@ package rpccache
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/localcache"
pbconv "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/rpccall" pbconversation "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
@ -33,10 +32,11 @@ const (
conversationWorkerCount = 20 conversationWorkerCount = 20
) )
func NewConversationLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *ConversationLocalCache { func NewConversationLocalCache(client *rpcli.ConversationClient, localCache *config.LocalCache, cli redis.UniversalClient) *ConversationLocalCache {
lc := localCache.Conversation lc := localCache.Conversation
log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
x := &ConversationLocalCache{ x := &ConversationLocalCache{
client: client,
local: localcache.New[[]byte]( local: localcache.New[[]byte](
localcache.WithLocalSlotNum(lc.SlotNum), localcache.WithLocalSlotNum(lc.SlotNum),
localcache.WithLocalSlotSize(lc.SlotSize), localcache.WithLocalSlotSize(lc.SlotSize),
@ -52,7 +52,8 @@ func NewConversationLocalCache(localCache *config.LocalCache, cli redis.Universa
} }
type ConversationLocalCache struct { type ConversationLocalCache struct {
local localcache.Cache[[]byte] client *rpcli.ConversationClient
local localcache.Cache[[]byte]
} }
func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUserID string) (val []string, err error) { func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUserID string) (val []string, err error) {
@ -63,7 +64,7 @@ func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUs
return resp.ConversationIDs, nil return resp.ConversationIDs, nil
} }
func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUserID string) (val *pbconv.GetConversationIDsResp, err error) { func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUserID string) (val *pbconversation.GetConversationIDsResp, err error) {
log.ZDebug(ctx, "ConversationLocalCache getConversationIDs req", "ownerUserID", ownerUserID) log.ZDebug(ctx, "ConversationLocalCache getConversationIDs req", "ownerUserID", ownerUserID)
defer func() { defer func() {
if err == nil { if err == nil {
@ -72,14 +73,14 @@ func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUs
log.ZError(ctx, "ConversationLocalCache getConversationIDs return", err, "ownerUserID", ownerUserID) log.ZError(ctx, "ConversationLocalCache getConversationIDs return", err, "ownerUserID", ownerUserID)
} }
}() }()
var cache cacheProto[pbconv.GetConversationIDsResp] var cache cacheProto[pbconversation.GetConversationIDsResp]
return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationIDsKey(ownerUserID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationIDsKey(ownerUserID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "ConversationLocalCache getConversationIDs rpc", "ownerUserID", ownerUserID) log.ZDebug(ctx, "ConversationLocalCache getConversationIDs rpc", "ownerUserID", ownerUserID)
return cache.Marshal(pbconv.GetConversationIDsCaller.Invoke(ctx, &pbconv.GetConversationIDsReq{UserID: ownerUserID})) return cache.Marshal(c.client.ConversationClient.GetConversationIDs(ctx, &pbconversation.GetConversationIDsReq{UserID: ownerUserID}))
})) }))
} }
func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconv.Conversation, err error) { func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconversation.Conversation, err error) {
log.ZDebug(ctx, "ConversationLocalCache GetConversation req", "userID", userID, "conversationID", conversationID) log.ZDebug(ctx, "ConversationLocalCache GetConversation req", "userID", userID, "conversationID", conversationID)
defer func() { defer func() {
if err == nil { if err == nil {
@ -88,13 +89,10 @@ func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, co
log.ZWarn(ctx, "ConversationLocalCache GetConversation return", err, "userID", userID, "conversationID", conversationID) log.ZWarn(ctx, "ConversationLocalCache GetConversation return", err, "userID", userID, "conversationID", conversationID)
} }
}() }()
var cache cacheProto[pbconv.Conversation] var cache cacheProto[pbconversation.Conversation]
return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationKey(userID, conversationID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationKey(userID, conversationID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "ConversationLocalCache GetConversation rpc", "userID", userID, "conversationID", conversationID) log.ZDebug(ctx, "ConversationLocalCache GetConversation rpc", "userID", userID, "conversationID", conversationID)
return cache.Marshal(rpccall.ExtractField(ctx, pbconv.GetConversationCaller.Invoke, &pbconv.GetConversationReq{ return cache.Marshal(c.client.GetConversation(ctx, conversationID, userID))
ConversationID: conversationID,
OwnerUserID: userID,
}, (*pbconv.GetConversationResp).GetConversation))
})) }))
} }
@ -106,10 +104,10 @@ func (c *ConversationLocalCache) GetSingleConversationRecvMsgOpt(ctx context.Con
return conv.RecvMsgOpt, nil return conv.RecvMsgOpt, nil
} }
func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconv.Conversation, error) { func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
var ( var (
conversations = make([]*pbconv.Conversation, 0, len(conversationIDs)) conversations = make([]*pbconversation.Conversation, 0, len(conversationIDs))
conversationsChan = make(chan *pbconv.Conversation, len(conversationIDs)) conversationsChan = make(chan *pbconversation.Conversation, len(conversationIDs))
) )
g, ctx := errgroup.WithContext(ctx) g, ctx := errgroup.WithContext(ctx)
@ -139,7 +137,7 @@ func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUser
return conversations, nil return conversations, nil
} }
func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (val *pbconv.GetConversationNotReceiveMessageUserIDsResp, err error) { func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (val *pbconversation.GetConversationNotReceiveMessageUserIDsResp, err error) {
log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs req", "conversationID", conversationID) log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs req", "conversationID", conversationID)
defer func() { defer func() {
if err == nil { if err == nil {
@ -148,10 +146,10 @@ func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx con
log.ZError(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs return", err, "conversationID", conversationID) log.ZError(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs return", err, "conversationID", conversationID)
} }
}() }()
var cache cacheProto[pbconv.GetConversationNotReceiveMessageUserIDsResp] var cache cacheProto[pbconversation.GetConversationNotReceiveMessageUserIDsResp]
return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs rpc", "conversationID", conversationID) log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs rpc", "conversationID", conversationID)
return cache.Marshal(pbconv.GetConversationNotReceiveMessageUserIDsCaller.Invoke(ctx, &pbconv.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID})) return cache.Marshal(c.client.ConversationClient.GetConversationNotReceiveMessageUserIDs(ctx, &pbconversation.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID}))
})) }))
} }

@ -16,8 +16,8 @@ package rpccache
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@ -26,10 +26,11 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
func NewFriendLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *FriendLocalCache { func NewFriendLocalCache(client *rpcli.RelationClient, localCache *config.LocalCache, cli redis.UniversalClient) *FriendLocalCache {
lc := localCache.Friend lc := localCache.Friend
log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
x := &FriendLocalCache{ x := &FriendLocalCache{
client: client,
local: localcache.New[[]byte]( local: localcache.New[[]byte](
localcache.WithLocalSlotNum(lc.SlotNum), localcache.WithLocalSlotNum(lc.SlotNum),
localcache.WithLocalSlotSize(lc.SlotSize), localcache.WithLocalSlotSize(lc.SlotSize),
@ -45,7 +46,8 @@ func NewFriendLocalCache(localCache *config.LocalCache, cli redis.UniversalClien
} }
type FriendLocalCache struct { type FriendLocalCache struct {
local localcache.Cache[[]byte] client *rpcli.RelationClient
local localcache.Cache[[]byte]
} }
func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (val bool, err error) { func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (val bool, err error) {
@ -68,7 +70,7 @@ func (f *FriendLocalCache) isFriend(ctx context.Context, possibleFriendUserID, u
var cache cacheProto[relation.IsFriendResp] var cache cacheProto[relation.IsFriendResp]
return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "FriendLocalCache isFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID) log.ZDebug(ctx, "FriendLocalCache isFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID)
return cache.Marshal(relation.IsFriendCaller.Invoke(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID})) return cache.Marshal(f.client.FriendClient.IsFriend(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}))
}, cachekey.GetFriendIDsKey(possibleFriendUserID))) }, cachekey.GetFriendIDsKey(possibleFriendUserID)))
} }
@ -94,6 +96,6 @@ func (f *FriendLocalCache) isBlack(ctx context.Context, possibleBlackUserID, use
var cache cacheProto[relation.IsBlackResp] var cache cacheProto[relation.IsBlackResp]
return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID) log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID)
return cache.Marshal(relation.IsBlackCaller.Invoke(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID})) return cache.Marshal(f.client.FriendClient.IsBlack(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}))
}, cachekey.GetBlackIDsKey(userID))) }, cachekey.GetBlackIDsKey(userID)))
} }

@ -16,10 +16,9 @@ package rpccache
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@ -30,10 +29,11 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
func NewGroupLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *GroupLocalCache { func NewGroupLocalCache(client *rpcli.GroupClient, localCache *config.LocalCache, cli redis.UniversalClient) *GroupLocalCache {
lc := localCache.Group lc := localCache.Group
log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
x := &GroupLocalCache{ x := &GroupLocalCache{
client: client,
local: localcache.New[[]byte]( local: localcache.New[[]byte](
localcache.WithLocalSlotNum(lc.SlotNum), localcache.WithLocalSlotNum(lc.SlotNum),
localcache.WithLocalSlotSize(lc.SlotSize), localcache.WithLocalSlotSize(lc.SlotSize),
@ -49,7 +49,8 @@ func NewGroupLocalCache(localCache *config.LocalCache, cli redis.UniversalClient
} }
type GroupLocalCache struct { type GroupLocalCache struct {
local localcache.Cache[[]byte] client *rpcli.GroupClient
local localcache.Cache[[]byte]
} }
func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string) (val *group.GetGroupMemberUserIDsResp, err error) { func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string) (val *group.GetGroupMemberUserIDsResp, err error) {
@ -64,7 +65,7 @@ func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string)
var cache cacheProto[group.GetGroupMemberUserIDsResp] var cache cacheProto[group.GetGroupMemberUserIDsResp]
return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberIDsKey(groupID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberIDsKey(groupID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs rpc", "groupID", groupID) log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs rpc", "groupID", groupID)
return cache.Marshal(group.GetGroupMemberUserIDsCaller.Invoke(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID})) return cache.Marshal(g.client.GroupClient.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID}))
})) }))
} }
@ -80,13 +81,7 @@ func (g *GroupLocalCache) GetGroupMember(ctx context.Context, groupID, userID st
var cache cacheProto[sdkws.GroupMemberFullInfo] var cache cacheProto[sdkws.GroupMemberFullInfo]
return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberInfoKey(groupID, userID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberInfoKey(groupID, userID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID, "userID", userID) log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID, "userID", userID)
return cache.Marshal(rpccall.ExtractField(ctx, group.GetGroupMemberCacheCaller.Invoke, return cache.Marshal(g.client.GetGroupMemberCache(ctx, groupID, userID))
&group.GetGroupMemberCacheReq{
GroupID: groupID,
GroupMemberID: userID,
},
(*group.GetGroupMemberCacheResp).GetMember,
))
})) }))
} }
@ -102,10 +97,7 @@ func (g *GroupLocalCache) GetGroupInfo(ctx context.Context, groupID string) (val
var cache cacheProto[sdkws.GroupInfo] var cache cacheProto[sdkws.GroupInfo]
return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupInfoKey(groupID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupInfoKey(groupID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID) log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID)
return cache.Marshal(rpccall.ExtractField(ctx, group.GetGroupInfoCacheCaller.Invoke, return cache.Marshal(g.client.GetGroupInfoCache(ctx, groupID))
&group.GetGroupInfoCacheReq{
GroupID: groupID,
}, (*group.GetGroupInfoCacheResp).GetGroupInfo))
})) }))
} }

@ -3,16 +3,15 @@ package rpccache
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/user"
"math/rand" "math/rand"
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/rpccall"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/localcache/lru" "github.com/openimsdk/open-im-server/v3/pkg/localcache/lru"
@ -23,10 +22,10 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
func NewOnlineCache(adminUserID []string, group *GroupLocalCache, rdb redis.UniversalClient, fullUserCache bool, fn func(ctx context.Context, userID string, platformIDs []int32)) (*OnlineCache, error) { func NewOnlineCache(client *rpcli.UserClient, group *GroupLocalCache, rdb redis.UniversalClient, fullUserCache bool, fn func(ctx context.Context, userID string, platformIDs []int32)) (*OnlineCache, error) {
l := &sync.Mutex{} l := &sync.Mutex{}
x := &OnlineCache{ x := &OnlineCache{
adminUserID: adminUserID, client: client,
group: group, group: group,
fullUserCache: fullUserCache, fullUserCache: fullUserCache,
Lock: l, Lock: l,
@ -66,8 +65,8 @@ const (
) )
type OnlineCache struct { type OnlineCache struct {
adminUserID []string client *rpcli.UserClient
group *GroupLocalCache group *GroupLocalCache
// fullUserCache if enabled, caches the online status of all users using mapCache; // fullUserCache if enabled, caches the online status of all users using mapCache;
// otherwise, only a portion of users' online statuses (regardless of whether they are online) will be cached using lruCache. // otherwise, only a portion of users' online statuses (regardless of whether they are online) will be cached using lruCache.
@ -113,7 +112,7 @@ func (o *OnlineCache) initUsersOnlineStatus(ctx context.Context) (err error) {
cursor := uint64(0) cursor := uint64(0)
for resp == nil || resp.NextCursor != 0 { for resp == nil || resp.NextCursor != 0 {
if err = retryOperation(func() error { if err = retryOperation(func() error {
resp, err = user.GetAllOnlineUsersCaller.Invoke(ctx, &user.GetAllOnlineUsersReq{Cursor: cursor}) resp, err = o.client.GetAllOnlineUsers(ctx, cursor)
if err != nil { if err != nil {
return err return err
} }
@ -187,17 +186,7 @@ func (o *OnlineCache) doSubscribe(ctx context.Context, rdb redis.UniversalClient
func (o *OnlineCache) getUserOnlinePlatform(ctx context.Context, userID string) ([]int32, error) { func (o *OnlineCache) getUserOnlinePlatform(ctx context.Context, userID string) ([]int32, error) {
platformIDs, err := o.lruCache.Get(userID, func() ([]int32, error) { platformIDs, err := o.lruCache.Get(userID, func() ([]int32, error) {
resp, err := rpccall.ExtractField(ctx, user.GetUserStatusCaller.Invoke, &user.GetUserStatusReq{ return o.client.GetUserOnlinePlatform(ctx, userID)
UserID: o.adminUserID[0],
UserIDs: []string{userID},
}, (*user.GetUserStatusResp).GetStatusList)
if err != nil {
return nil, err
}
if len(resp) == 0 {
return nil, nil
}
return resp[0].PlatformIDs, nil
}) })
if err != nil { if err != nil {
log.ZError(ctx, "OnlineCache GetUserOnlinePlatform", err, "userID", userID) log.ZError(ctx, "OnlineCache GetUserOnlinePlatform", err, "userID", userID)
@ -238,11 +227,7 @@ func (o *OnlineCache) GetUserOnline(ctx context.Context, userID string) (bool, e
func (o *OnlineCache) getUserOnlinePlatformBatch(ctx context.Context, userIDs []string) (map[string][]int32, error) { func (o *OnlineCache) getUserOnlinePlatformBatch(ctx context.Context, userIDs []string) (map[string][]int32, error) {
platformIDsMap, err := o.lruCache.GetBatch(userIDs, func(missingUsers []string) (map[string][]int32, error) { platformIDsMap, err := o.lruCache.GetBatch(userIDs, func(missingUsers []string) (map[string][]int32, error) {
platformIDsMap := make(map[string][]int32) platformIDsMap := make(map[string][]int32)
usersStatus, err := o.client.GetUsersOnlinePlatform(ctx, missingUsers)
usersStatus, err := rpccall.ExtractField(ctx, user.GetUserStatusCaller.Invoke, &user.GetUserStatusReq{
UserID: o.adminUserID[0],
UserIDs: missingUsers,
}, (*user.GetUserStatusResp).GetStatusList)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -17,7 +17,6 @@ package rpccache
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )

@ -16,11 +16,11 @@ package rpccache
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
"github.com/openimsdk/open-im-server/v3/pkg/localcache" "github.com/openimsdk/open-im-server/v3/pkg/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/user" "github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
@ -28,10 +28,11 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
func NewUserLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *UserLocalCache { func NewUserLocalCache(client *rpcli.UserClient, localCache *config.LocalCache, cli redis.UniversalClient) *UserLocalCache {
lc := localCache.User lc := localCache.User
log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable()) log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
x := &UserLocalCache{ x := &UserLocalCache{
client: client,
local: localcache.New[[]byte]( local: localcache.New[[]byte](
localcache.WithLocalSlotNum(lc.SlotNum), localcache.WithLocalSlotNum(lc.SlotNum),
localcache.WithLocalSlotSize(lc.SlotSize), localcache.WithLocalSlotSize(lc.SlotSize),
@ -47,7 +48,8 @@ func NewUserLocalCache(localCache *config.LocalCache, cli redis.UniversalClient)
} }
type UserLocalCache struct { type UserLocalCache struct {
local localcache.Cache[[]byte] client *rpcli.UserClient
local localcache.Cache[[]byte]
} }
func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *sdkws.UserInfo, err error) { func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *sdkws.UserInfo, err error) {
@ -62,7 +64,7 @@ func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *s
var cache cacheProto[sdkws.UserInfo] var cache cacheProto[sdkws.UserInfo]
return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserInfoKey(userID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserInfoKey(userID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "UserLocalCache GetUserInfo rpc", "userID", userID) log.ZDebug(ctx, "UserLocalCache GetUserInfo rpc", "userID", userID)
return cache.Marshal(rpcclient.GetUserInfo(ctx, userID)) return cache.Marshal(u.client.GetUserInfo(ctx, userID))
})) }))
} }
@ -86,7 +88,7 @@ func (u *UserLocalCache) getUserGlobalMsgRecvOpt(ctx context.Context, userID str
var cache cacheProto[user.GetGlobalRecvMessageOptResp] var cache cacheProto[user.GetGlobalRecvMessageOptResp]
return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserGlobalRecvMsgOptKey(userID), func(ctx context.Context) ([]byte, error) { return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserGlobalRecvMsgOptKey(userID), func(ctx context.Context) ([]byte, error) {
log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt rpc", "userID", userID) log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt rpc", "userID", userID)
return cache.Marshal(user.GetGlobalRecvMessageOptCaller.Invoke(ctx, &user.GetGlobalRecvMessageOptReq{UserID: userID})) return cache.Marshal(u.client.UserClient.GetGlobalRecvMessageOpt(ctx, &user.GetGlobalRecvMessageOptReq{UserID: userID}))
})) }))
} }

@ -1,15 +0,0 @@
// Copyright © 2024 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 rpcclient // import "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"

@ -1,15 +0,0 @@
// Copyright © 2024 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 grouphash // import "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"

@ -1,60 +0,0 @@
package rpcclient
import (
"context"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
pbauth "github.com/openimsdk/protocol/auth"
pbconversation "github.com/openimsdk/protocol/conversation"
pbgroup "github.com/openimsdk/protocol/group"
pbmsg "github.com/openimsdk/protocol/msg"
pbmsggateway "github.com/openimsdk/protocol/msggateway"
pbpush "github.com/openimsdk/protocol/push"
pbrelation "github.com/openimsdk/protocol/relation"
pbthird "github.com/openimsdk/protocol/third"
pbuser "github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/system/program"
"google.golang.org/grpc"
)
func InitRpcCaller(discov discovery.SvcDiscoveryRegistry, service config.RpcService) error {
initConn := func(discov discovery.SvcDiscoveryRegistry, name string, initFunc func(conn *grpc.ClientConn)) error {
conn, err := discov.GetConn(context.Background(), name)
if err != nil {
program.ExitWithError(err)
return err
}
initFunc(conn)
return nil
}
if err := initConn(discov, service.Auth, pbauth.InitAuth); err != nil {
return err
}
if err := initConn(discov, service.Conversation, pbconversation.InitConversation); err != nil {
return err
}
if err := initConn(discov, service.Group, pbgroup.InitGroup); err != nil {
return err
}
if err := initConn(discov, service.Msg, pbmsg.InitMsg); err != nil {
return err
}
if err := initConn(discov, service.MessageGateway, pbmsggateway.InitMsgGateway); err != nil {
return err
}
if err := initConn(discov, service.Push, pbpush.InitPushMsgService); err != nil {
return err
}
if err := initConn(discov, service.Friend, pbrelation.InitFriend); err != nil {
return err
}
if err := initConn(discov, service.Third, pbthird.InitThird); err != nil {
return err
}
if err := initConn(discov, service.User, pbuser.InitUser); err != nil {
return err
}
return nil
}

@ -1,15 +0,0 @@
// Copyright © 2024 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 notification // import "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"

@ -1,109 +0,0 @@
// 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 rpcclient
import (
"context"
"strings"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
"github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/utils/datautil"
)
// GetUsersInfo retrieves information for multiple users based on their user IDs.
func GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) {
if len(userIDs) == 0 {
return []*sdkws.UserInfo{}, nil
}
resp, err := user.GetDesignateUsersCaller.Invoke(ctx, &user.GetDesignateUsersReq{
UserIDs: userIDs,
})
if err != nil {
return nil, err
}
if ids := datautil.Single(userIDs, datautil.Slice(resp.UsersInfo, func(e *sdkws.UserInfo) string {
return e.UserID
})); len(ids) > 0 {
return nil, servererrs.ErrUserIDNotFound.WrapMsg(strings.Join(ids, ","))
}
return resp.UsersInfo, nil
}
// GetUserInfo retrieves information for a single user based on the provided user ID.
func GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) {
users, err := GetUsersInfo(ctx, []string{userID})
if err != nil {
return nil, err
}
return users[0], nil
}
// GetUsersInfoMap retrieves a map of user information indexed by their user IDs.
func GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
users, err := GetUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.SliceToMap(users, func(e *sdkws.UserInfo) string {
return e.UserID
}), nil
}
// GetPublicUserInfos retrieves public information for multiple users based on their user IDs.
func GetPublicUserInfos(
ctx context.Context,
userIDs []string,
) ([]*sdkws.PublicUserInfo, error) {
users, err := GetUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.Slice(users, func(e *sdkws.UserInfo) *sdkws.PublicUserInfo {
return &sdkws.PublicUserInfo{
UserID: e.UserID,
Nickname: e.Nickname,
FaceURL: e.FaceURL,
Ex: e.Ex,
}
}), nil
}
// GetPublicUserInfo retrieves public information for a single user based on the provided user ID.
func GetPublicUserInfo(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
users, err := GetPublicUserInfos(ctx, []string{userID})
if err != nil {
return nil, err
}
return users[0], nil
}
// GetPublicUserInfoMap retrieves a map of public user information indexed by their user IDs.
func GetPublicUserInfoMap(
ctx context.Context,
userIDs []string,
) (map[string]*sdkws.PublicUserInfo, error) {
users, err := GetPublicUserInfos(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.SliceToMap(users, func(e *sdkws.PublicUserInfo) string {
return e.UserID
}), nil
}

@ -0,0 +1,30 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/auth"
"google.golang.org/grpc"
)
func NewAuthClient(cc grpc.ClientConnInterface) *AuthClient {
return &AuthClient{auth.NewAuthClient(cc)}
}
type AuthClient struct {
auth.AuthClient
}
func (x *AuthClient) KickTokens(ctx context.Context, tokens []string) error {
if len(tokens) == 0 {
return nil
}
return ignoreResp(x.AuthClient.KickTokens(ctx, &auth.KickTokensReq{Tokens: tokens}))
}
func (x *AuthClient) InvalidateToken(ctx context.Context, req *auth.InvalidateTokenReq) error {
return ignoreResp(x.AuthClient.InvalidateToken(ctx, req))
}
func (x *AuthClient) ParseToken(ctx context.Context, token string) (*auth.ParseTokenResp, error) {
return x.AuthClient.ParseToken(ctx, &auth.ParseTokenReq{Token: token})
}

@ -0,0 +1,94 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/conversation"
"google.golang.org/grpc"
)
func NewConversationClient(cc grpc.ClientConnInterface) *ConversationClient {
return &ConversationClient{conversation.NewConversationClient(cc)}
}
type ConversationClient struct {
conversation.ConversationClient
}
func (x *ConversationClient) SetConversationMaxSeq(ctx context.Context, conversationID string, ownerUserIDs []string, maxSeq int64) error {
if len(ownerUserIDs) == 0 {
return nil
}
req := &conversation.SetConversationMaxSeqReq{ConversationID: conversationID, OwnerUserID: ownerUserIDs, MaxSeq: maxSeq}
return ignoreResp(x.ConversationClient.SetConversationMaxSeq(ctx, req))
}
func (x *ConversationClient) SetConversations(ctx context.Context, ownerUserIDs []string, info *conversation.ConversationReq) error {
if len(ownerUserIDs) == 0 {
return nil
}
req := &conversation.SetConversationsReq{UserIDs: ownerUserIDs, Conversation: info}
return ignoreResp(x.ConversationClient.SetConversations(ctx, req))
}
func (x *ConversationClient) GetConversationsByConversationIDs(ctx context.Context, conversationIDs []string) ([]*conversation.Conversation, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
req := &conversation.GetConversationsByConversationIDReq{ConversationIDs: conversationIDs}
return extractField(ctx, x.ConversationClient.GetConversationsByConversationID, req, (*conversation.GetConversationsByConversationIDResp).GetConversations)
}
func (x *ConversationClient) GetConversationsByConversationID(ctx context.Context, conversationID string) (*conversation.Conversation, error) {
return firstValue(x.GetConversationsByConversationIDs(ctx, []string{conversationID}))
}
func (x *ConversationClient) SetConversationMinSeq(ctx context.Context, conversationID string, ownerUserIDs []string, minSeq int64) error {
if len(ownerUserIDs) == 0 {
return nil
}
req := &conversation.SetConversationMinSeqReq{ConversationID: conversationID, OwnerUserID: ownerUserIDs, MinSeq: minSeq}
return ignoreResp(x.ConversationClient.SetConversationMinSeq(ctx, req))
}
func (x *ConversationClient) GetConversation(ctx context.Context, conversationID string, ownerUserID string) (*conversation.Conversation, error) {
req := &conversation.GetConversationReq{ConversationID: conversationID, OwnerUserID: ownerUserID}
return extractField(ctx, x.ConversationClient.GetConversation, req, (*conversation.GetConversationResp).GetConversation)
}
func (x *ConversationClient) GetConversations(ctx context.Context, conversationIDs []string, ownerUserID string) ([]*conversation.Conversation, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
req := &conversation.GetConversationsReq{ConversationIDs: conversationIDs, OwnerUserID: ownerUserID}
return extractField(ctx, x.ConversationClient.GetConversations, req, (*conversation.GetConversationsResp).GetConversations)
}
func (x *ConversationClient) GetConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
req := &conversation.GetConversationIDsReq{UserID: ownerUserID}
return extractField(ctx, x.ConversationClient.GetConversationIDs, req, (*conversation.GetConversationIDsResp).GetConversationIDs)
}
func (x *ConversationClient) GetPinnedConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
req := &conversation.GetPinnedConversationIDsReq{UserID: ownerUserID}
return extractField(ctx, x.ConversationClient.GetPinnedConversationIDs, req, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
}
func (x *ConversationClient) CreateGroupChatConversations(ctx context.Context, groupID string, userIDs []string) error {
if len(userIDs) == 0 {
return nil
}
req := &conversation.CreateGroupChatConversationsReq{GroupID: groupID, UserIDs: userIDs}
return ignoreResp(x.ConversationClient.CreateGroupChatConversations(ctx, req))
}
func (x *ConversationClient) CreateSingleChatConversations(ctx context.Context, req *conversation.CreateSingleChatConversationsReq) error {
return ignoreResp(x.ConversationClient.CreateSingleChatConversations(ctx, req))
}
func (x *ConversationClient) GetConversationOfflinePushUserIDs(ctx context.Context, conversationID string, userIDs []string) ([]string, error) {
if len(userIDs) == 0 {
return nil, nil
}
req := &conversation.GetConversationOfflinePushUserIDsReq{ConversationID: conversationID, UserIDs: userIDs}
return extractField(ctx, x.ConversationClient.GetConversationOfflinePushUserIDs, req, (*conversation.GetConversationOfflinePushUserIDsResp).GetUserIDs)
}

@ -0,0 +1,48 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/sdkws"
"google.golang.org/grpc"
)
func NewGroupClient(cc grpc.ClientConnInterface) *GroupClient {
return &GroupClient{group.NewGroupClient(cc)}
}
type GroupClient struct {
group.GroupClient
}
func (x *GroupClient) GetGroupsInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) {
if len(groupIDs) == 0 {
return nil, nil
}
req := &group.GetGroupsInfoReq{GroupIDs: groupIDs}
return extractField(ctx, x.GroupClient.GetGroupsInfo, req, (*group.GetGroupsInfoResp).GetGroupInfos)
}
func (x *GroupClient) GetGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
return firstValue(x.GetGroupsInfo(ctx, []string{groupID}))
}
func (x *GroupClient) GetGroupInfoCache(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
req := &group.GetGroupInfoCacheReq{GroupID: groupID}
return extractField(ctx, x.GroupClient.GetGroupInfoCache, req, (*group.GetGroupInfoCacheResp).GetGroupInfo)
}
func (x *GroupClient) GetGroupMemberCache(ctx context.Context, groupID string, userID string) (*sdkws.GroupMemberFullInfo, error) {
req := &group.GetGroupMemberCacheReq{GroupID: groupID, GroupMemberID: userID}
return extractField(ctx, x.GroupClient.GetGroupMemberCache, req, (*group.GetGroupMemberCacheResp).GetMember)
}
func (x *GroupClient) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error {
req := &group.DismissGroupReq{GroupID: groupID, DeleteMember: deleteMember}
return ignoreResp(x.GroupClient.DismissGroup(ctx, req))
}
func (x *GroupClient) GetGroupMemberUserIDs(ctx context.Context, groupID string) ([]string, error) {
req := &group.GetGroupMemberUserIDsReq{GroupID: groupID}
return extractField(ctx, x.GroupClient.GetGroupMemberUserIDs, req, (*group.GetGroupMemberUserIDsResp).GetUserIDs)
}

@ -0,0 +1,90 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/sdkws"
"google.golang.org/grpc"
)
func NewMsgClient(cc grpc.ClientConnInterface) *MsgClient {
return &MsgClient{msg.NewMsgClient(cc)}
}
type MsgClient struct {
msg.MsgClient
}
func (x *MsgClient) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
req := &msg.GetMaxSeqsReq{ConversationIDs: conversationIDs}
return extractField(ctx, x.MsgClient.GetMaxSeqs, req, (*msg.SeqsInfoResp).GetMaxSeqs)
}
func (x *MsgClient) GetMsgByConversationIDs(ctx context.Context, conversationIDs []string, maxSeqs map[string]int64) (map[string]*sdkws.MsgData, error) {
if len(conversationIDs) == 0 || len(maxSeqs) == 0 {
return nil, nil
}
req := &msg.GetMsgByConversationIDsReq{ConversationIDs: conversationIDs, MaxSeqs: maxSeqs}
return extractField(ctx, x.MsgClient.GetMsgByConversationIDs, req, (*msg.GetMsgByConversationIDsResp).GetMsgDatas)
}
func (x *MsgClient) GetHasReadSeqs(ctx context.Context, conversationIDs []string, userID string) (map[string]int64, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
req := &msg.GetHasReadSeqsReq{ConversationIDs: conversationIDs, UserID: userID}
return extractField(ctx, x.MsgClient.GetHasReadSeqs, req, (*msg.SeqsInfoResp).GetMaxSeqs)
}
func (x *MsgClient) SetUserConversationMaxSeq(ctx context.Context, conversationID string, ownerUserIDs []string, maxSeq int64) error {
if len(ownerUserIDs) == 0 {
return nil
}
req := &msg.SetUserConversationMaxSeqReq{ConversationID: conversationID, OwnerUserID: ownerUserIDs, MaxSeq: maxSeq}
return ignoreResp(x.MsgClient.SetUserConversationMaxSeq(ctx, req))
}
func (x *MsgClient) SetUserConversationMin(ctx context.Context, conversationID string, ownerUserIDs []string, minSeq int64) error {
if len(ownerUserIDs) == 0 {
return nil
}
req := &msg.SetUserConversationsMinSeqReq{ConversationID: conversationID, UserIDs: ownerUserIDs, Seq: minSeq}
return ignoreResp(x.MsgClient.SetUserConversationsMinSeq(ctx, req))
}
func (x *MsgClient) GetLastMessageSeqByTime(ctx context.Context, conversationID string, lastTime int64) (int64, error) {
req := &msg.GetLastMessageSeqByTimeReq{ConversationID: conversationID, Time: lastTime}
return extractField(ctx, x.MsgClient.GetLastMessageSeqByTime, req, (*msg.GetLastMessageSeqByTimeResp).GetSeq)
}
func (x *MsgClient) GetConversationMaxSeq(ctx context.Context, conversationID string) (int64, error) {
req := &msg.GetConversationMaxSeqReq{ConversationID: conversationID}
return extractField(ctx, x.MsgClient.GetConversationMaxSeq, req, (*msg.GetConversationMaxSeqResp).GetMaxSeq)
}
func (x *MsgClient) GetActiveConversation(ctx context.Context, conversationIDs []string) ([]*msg.ActiveConversation, error) {
if len(conversationIDs) == 0 {
return nil, nil
}
req := &msg.GetActiveConversationReq{ConversationIDs: conversationIDs}
return extractField(ctx, x.MsgClient.GetActiveConversation, req, (*msg.GetActiveConversationResp).GetConversations)
}
func (x *MsgClient) GetSeqMessage(ctx context.Context, userID string, conversations []*msg.ConversationSeqs) (map[string]*sdkws.PullMsgs, error) {
if len(conversations) == 0 {
return nil, nil
}
req := &msg.GetSeqMessageReq{UserID: userID, Conversations: conversations}
return extractField(ctx, x.MsgClient.GetSeqMessage, req, (*msg.GetSeqMessageResp).GetMsgs)
}
func (x *MsgClient) SetUserConversationsMinSeq(ctx context.Context, conversationID string, userIDs []string, seq int64) error {
if len(userIDs) == 0 {
return nil
}
req := &msg.SetUserConversationsMinSeqReq{ConversationID: conversationID, UserIDs: userIDs, Seq: seq}
return ignoreResp(x.MsgClient.SetUserConversationsMinSeq(ctx, req))
}

@ -0,0 +1,14 @@
package rpcli
import (
"github.com/openimsdk/protocol/msggateway"
"google.golang.org/grpc"
)
func NewMsgGatewayClient(cc grpc.ClientConnInterface) *MsgGatewayClient {
return &MsgGatewayClient{msggateway.NewMsgGatewayClient(cc)}
}
type MsgGatewayClient struct {
msggateway.MsgGatewayClient
}

@ -0,0 +1,14 @@
package rpcli
import (
"github.com/openimsdk/protocol/push"
"google.golang.org/grpc"
)
func NewPushMsgServiceClient(cc grpc.ClientConnInterface) *PushMsgServiceClient {
return &PushMsgServiceClient{push.NewPushMsgServiceClient(cc)}
}
type PushMsgServiceClient struct {
push.PushMsgServiceClient
}

@ -0,0 +1,23 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/relation"
"google.golang.org/grpc"
)
func NewRelationClient(cc grpc.ClientConnInterface) *RelationClient {
return &RelationClient{relation.NewFriendClient(cc)}
}
type RelationClient struct {
relation.FriendClient
}
func (x *RelationClient) GetFriendsInfo(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*relation.FriendInfoOnly, error) {
if len(friendUserIDs) == 0 {
return nil, nil
}
req := &relation.GetFriendInfoReq{OwnerUserID: ownerUserID, FriendUserIDs: friendUserIDs}
return extractField(ctx, x.FriendClient.GetFriendInfo, req, (*relation.GetFriendInfoResp).GetFriendInfos)
}

@ -0,0 +1,14 @@
package rpcli
import (
"github.com/openimsdk/protocol/rtc"
"google.golang.org/grpc"
)
func NewRtcServiceClient(cc grpc.ClientConnInterface) *RtcServiceClient {
return &RtcServiceClient{rtc.NewRtcServiceClient(cc)}
}
type RtcServiceClient struct {
rtc.RtcServiceClient
}

@ -0,0 +1,14 @@
package rpcli
import (
"github.com/openimsdk/protocol/third"
"google.golang.org/grpc"
)
func NewThirdClient(cc grpc.ClientConnInterface) *ThirdClient {
return &ThirdClient{third.NewThirdClient(cc)}
}
type ThirdClient struct {
third.ThirdClient
}

@ -0,0 +1,32 @@
package rpcli
import (
"context"
"github.com/openimsdk/tools/errs"
"google.golang.org/grpc"
)
func extractField[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
resp, err := fn(ctx, req)
if err != nil {
var c C
return c, err
}
return get(resp), nil
}
func firstValue[A any](val []A, err error) (A, error) {
if err != nil {
var a A
return a, err
}
if len(val) == 0 {
var a A
return a, errs.ErrRecordNotFound.WrapMsg("record not found")
}
return val[0], nil
}
func ignoreResp(_ any, err error) error {
return err
}

@ -0,0 +1,95 @@
package rpcli
import (
"context"
"github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/utils/datautil"
"google.golang.org/grpc"
)
func NewUserClient(cc grpc.ClientConnInterface) *UserClient {
return &UserClient{user.NewUserClient(cc)}
}
type UserClient struct {
user.UserClient
}
func (x *UserClient) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) {
if len(userIDs) == 0 {
return nil, nil
}
req := &user.GetDesignateUsersReq{UserIDs: userIDs}
return extractField(ctx, x.UserClient.GetDesignateUsers, req, (*user.GetDesignateUsersResp).GetUsersInfo)
}
func (x *UserClient) GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) {
return firstValue(x.GetUsersInfo(ctx, []string{userID}))
}
func (x *UserClient) CheckUser(ctx context.Context, userIDs []string) error {
if len(userIDs) == 0 {
return nil
}
users, err := x.GetUsersInfo(ctx, userIDs)
if err != nil {
return err
}
if len(users) != len(userIDs) {
return errs.ErrRecordNotFound.WrapMsg("user not found")
}
return nil
}
func (x *UserClient) GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
users, err := x.GetUsersInfo(ctx, userIDs)
if err != nil {
return nil, err
}
return datautil.SliceToMap(users, func(e *sdkws.UserInfo) string {
return e.UserID
}), nil
}
func (x *UserClient) GetAllOnlineUsers(ctx context.Context, cursor uint64) (*user.GetAllOnlineUsersResp, error) {
req := &user.GetAllOnlineUsersReq{Cursor: cursor}
return x.UserClient.GetAllOnlineUsers(ctx, req)
}
func (x *UserClient) GetUsersOnlinePlatform(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) {
if len(userIDs) == 0 {
return nil, nil
}
req := &user.GetUserStatusReq{UserIDs: userIDs}
return extractField(ctx, x.UserClient.GetUserStatus, req, (*user.GetUserStatusResp).GetStatusList)
}
func (x *UserClient) GetUserOnlinePlatform(ctx context.Context, userID string) ([]int32, error) {
status, err := x.GetUsersOnlinePlatform(ctx, []string{userID})
if err != nil {
return nil, err
}
if len(status) == 0 {
return nil, nil
}
return status[0].PlatformIDs, nil
}
func (x *UserClient) SetUserOnlineStatus(ctx context.Context, req *user.SetUserOnlineStatusReq) error {
if len(req.Status) == 0 {
return nil
}
return ignoreResp(x.UserClient.SetUserOnlineStatus(ctx, req))
}
func (x *UserClient) GetNotificationByID(ctx context.Context, userID string) error {
return ignoreResp(x.UserClient.GetNotificationAccount(ctx, &user.GetNotificationAccountReq{UserID: userID}))
}
func (x *UserClient) GetAllUserIDs(ctx context.Context, pageNumber, showNumber int32) ([]string, error) {
req := &user.GetAllUserIDReq{Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}}
return extractField(ctx, x.UserClient.GetAllUserID, req, (*user.GetAllUserIDResp).GetUserIDs)
}
Loading…
Cancel
Save