From 1f34a1fb157a9e521d69058769f37e8b7b38b024 Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Fri, 23 May 2025 19:36:27 +0800 Subject: [PATCH 01/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- go.mod | 3 +- go.sum | 6 +- internal/conversation_msg/notification.go | 19 +-- internal/group/api.go | 28 ++-- internal/group/cache.go | 2 +- internal/group/conversion.go | 26 ++-- internal/group/filter.go | 52 +++++++ internal/group/full_sync.go | 92 ------------ internal/group/group.go | 88 ++--------- internal/group/notification.go | 60 +++----- internal/group/server_api.go | 12 +- internal/interaction/msg_sync.go | 19 ++- internal/relation/api.go | 30 ++-- internal/relation/conversion.go | 19 +-- internal/relation/notification.go | 17 +-- internal/relation/relation.go | 55 ------- internal/relation/server_api.go | 9 +- internal/relation/sync.go | 104 ------------- internal/user/full_sync.go | 5 +- open_im_sdk/init_login.go | 7 + open_im_sdk/userRelated.go | 4 + pkg/api/api.go | 52 +++---- pkg/constant/constant.go | 16 +- pkg/db/db_init.go | 3 - pkg/db/db_interface/databse.go | 16 -- pkg/db/db_js.go | 4 - pkg/db/friend_request_model.go | 76 ---------- pkg/db/group_request_model.go | 53 ------- pkg/sdk_params_callback/friend_sdk_struct.go | 11 ++ pkg/sdk_params_callback/group_sdk_struct.go | 14 ++ wasm/indexdb/friend_request_model.go | 149 ------------------- wasm/indexdb/group_request.model.go | 95 ------------ wasm/indexdb/init.go | 2 - 33 files changed, 252 insertions(+), 896 deletions(-) create mode 100644 internal/group/filter.go delete mode 100644 pkg/db/friend_request_model.go delete mode 100644 pkg/db/group_request_model.go delete mode 100644 wasm/indexdb/friend_request_model.go delete mode 100644 wasm/indexdb/group_request.model.go diff --git a/go.mod b/go.mod index 9f48c737f..0fb39cc72 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,8 @@ require golang.org/x/net v0.39.0 // indirect require ( github.com/google/go-cmp v0.6.0 - github.com/openimsdk/protocol v0.0.73-alpha.6 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/openimsdk/protocol v0.0.73-alpha.12 github.com/openimsdk/tools v0.0.50-alpha.80 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 111412906..7ccd86618 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -28,8 +30,8 @@ github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205Ah github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/openimsdk/protocol v0.0.73-alpha.6 h1:sna9coWG7HN1zObBPtvG0Ki/vzqHXiB4qKbA5P3w7kc= -github.com/openimsdk/protocol v0.0.73-alpha.6/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= +github.com/openimsdk/protocol v0.0.73-alpha.12 h1:2NYawXeHChYUeSme6QJ9pOLh+Empce2WmwEtbP4JvKk= +github.com/openimsdk/protocol v0.0.73-alpha.12/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= github.com/openimsdk/tools v0.0.50-alpha.80 h1:Nvt97Vm85CXr633Jf7WjRJeL2nxJJjwlZJFDgWWXkJU= github.com/openimsdk/tools v0.0.50-alpha.80/go.mod h1:n2poR3asX1e1XZce4O+MOWAp+X02QJRFvhcLCXZdzRo= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= diff --git a/internal/conversation_msg/notification.go b/internal/conversation_msg/notification.go index 156af44b1..d2f67969e 100644 --- a/internal/conversation_msg/notification.go +++ b/internal/conversation_msg/notification.go @@ -70,10 +70,12 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { seqs := c2v.Value.(sdk_struct.CmdNewMsgComeToConversation).Seqs switch syncFlag { case constant.AppDataSyncBegin, constant.LargeDataSyncBegin: + c.ConversationListener().OnSyncServerStart(true) + + case constant.AppDataSyncData, constant.LargeDataSyncData: log.ZDebug(ctx, "AppDataSyncBegin") c.seqs = seqs c.startTime = time.Now() - c.ConversationListener().OnSyncServerStart(true) c.ConversationListener().OnSyncServerProgress(1) asyncWaitFunctions := []func(c context.Context) error{ c.group.IncrSyncJoinGroup, @@ -96,10 +98,6 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { asyncNoWaitFunctions := []func(c context.Context) error{ c.user.SyncLoginUserInfoWithoutNotice, c.relation.SyncAllBlackListWithoutNotice, - c.relation.SyncAllFriendApplicationWithoutNotice, - c.relation.SyncAllSelfFriendApplicationWithoutNotice, - c.group.SyncAllAdminGroupApplicationWithoutNotice, - c.group.SyncAllSelfGroupApplicationWithoutNotice, } runSyncFunctions(ctx, asyncNoWaitFunctions, asyncNoWait) @@ -108,11 +106,14 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { c.progress = 100 c.ConversationListener().OnSyncServerProgress(c.progress) c.ConversationListener().OnSyncServerFinish(true) - case constant.MsgSyncBegin: + case constant.MsgSyncData: c.seqs = seqs log.ZDebug(ctx, "MsgSyncBegin") - c.ConversationListener().OnSyncServerStart(false) c.syncData(c2v) + + case constant.MsgSyncBegin: + c.ConversationListener().OnSyncServerStart(false) + case constant.MsgSyncFailed: c.ConversationListener().OnSyncServerFailed(false) case constant.MsgSyncEnd: @@ -434,10 +435,6 @@ func (c *Conversation) syncData(c2v common.Cmd2Value) { asyncFuncs := []func(c context.Context) error{ c.user.SyncLoginUserInfo, c.relation.SyncAllBlackList, - c.relation.SyncAllFriendApplication, - c.relation.SyncAllSelfFriendApplication, - c.group.SyncAllAdminGroupApplication, - c.group.SyncAllSelfGroupApplication, c.group.IncrSyncJoinGroupWithLock, c.relation.IncrSyncFriendsWithLock, c.IncrSyncConversationsWithLock, diff --git a/internal/group/api.go b/internal/group/api.go index ab0a51065..58c3b4d27 100644 --- a/internal/group/api.go +++ b/internal/group/api.go @@ -63,9 +63,9 @@ func (g *Group) JoinGroup(ctx context.Context, groupID, reqMsg string, joinSourc if err := g.joinGroup(ctx, req); err != nil { return err } - if err := g.SyncSelfGroupApplications(ctx, groupID); err != nil { - return err - } + //if err := g.SyncSelfGroupApplications(ctx, groupID); err != nil { + // return err + //} return nil } @@ -262,7 +262,7 @@ func (g *Group) GetGroupMemberListByJoinTimeFilter(ctx context.Context, groupID return localGroupMembers, true, err }, func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) { - serverGroupMember, err := g.GetDesignatedGroupMembers(ctx, groupID, userIDs) + serverGroupMember, err := g.getDesignatedGroupMembers(ctx, groupID, userIDs) if err != nil { return nil, err } @@ -321,7 +321,7 @@ func (g *Group) GetSpecifiedGroupMembersInfo(ctx context.Context, groupID string return localGroupMembers, true, nil }, func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) { - serverGroupMember, err := g.GetDesignatedGroupMembers(ctx, groupID, userIDs) + serverGroupMember, err := g.getDesignatedGroupMembers(ctx, groupID, userIDs) if err != nil { return nil, err } @@ -390,7 +390,7 @@ func (g *Group) GetGroupMemberList(ctx context.Context, groupID string, filter, return nil, false, sdkerrs.ErrArgs }, func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) { - serverGroupMember, err := g.GetDesignatedGroupMembers(ctx, groupID, userIDs) + serverGroupMember, err := g.getDesignatedGroupMembers(ctx, groupID, userIDs) if err != nil { return nil, err } @@ -414,12 +414,20 @@ func (g *Group) GetGroupMemberList(ctx context.Context, groupID string, filter, return dataFetcher.FetchWithPagination(ctx, int(offset), int(count)) } -func (g *Group) GetGroupApplicationListAsRecipient(ctx context.Context) ([]*model_struct.LocalAdminGroupRequest, error) { - return g.db.GetAdminGroupApplication(ctx) +func (g *Group) GetGroupApplicationListAsRecipient(ctx context.Context, req *sdk_params_callback.GetGroupApplicationListAsRecipientReq) ([]*model_struct.LocalGroupRequest, error) { + groupRequests, err := g.getServerAdminGroupApplicationList(ctx, req.GroupIDs, req.HandleResults, req.Offset/req.Count+1, req.Count) + if err != nil { + return nil, err + } + return datautil.Batch(ServerGroupRequestToLocalGroupRequest, groupRequests), nil } -func (g *Group) GetGroupApplicationListAsApplicant(ctx context.Context) ([]*model_struct.LocalGroupRequest, error) { - return g.db.GetSendGroupApplication(ctx) +func (g *Group) GetGroupApplicationListAsApplicant(ctx context.Context, req *sdk_params_callback.GetGroupApplicationListAsApplicantReq) ([]*model_struct.LocalGroupRequest, error) { + groupRequests, err := g.getServerSelfGroupApplication(ctx, req.GroupIDs, req.HandleResults, req.Offset/req.Count+1, req.Count) + if err != nil { + return nil, err + } + return datautil.Batch(ServerGroupRequestToLocalGroupRequest, groupRequests), nil } func (g *Group) SearchGroupMembers(ctx context.Context, searchParam *sdk_params_callback.SearchGroupMembersParam) ([]*model_struct.LocalGroupMember, error) { diff --git a/internal/group/cache.go b/internal/group/cache.go index 8678d2d49..bc1526499 100644 --- a/internal/group/cache.go +++ b/internal/group/cache.go @@ -57,7 +57,7 @@ func (g *Group) GetGroupMembersInfo(ctx context.Context, groupID string, userIDs return t.UserID }) if len(queryKeys) != 0 { - queryData, err := g.GetDesignatedGroupMembers(ctx, groupID, queryKeys) + queryData, err := g.getDesignatedGroupMembers(ctx, groupID, queryKeys) if err != nil { return nil, err } diff --git a/internal/group/conversion.go b/internal/group/conversion.go index 27d7be6fd..6f6e11837 100644 --- a/internal/group/conversion.go +++ b/internal/group/conversion.go @@ -39,7 +39,6 @@ func ServerGroupToLocalGroup(info *sdkws.GroupInfo) *model_struct.LocalGroup { ApplyMemberFriend: info.ApplyMemberFriend, NotificationUpdateTime: info.NotificationUpdateTime, NotificationUserID: info.NotificationUserID, - //AttachedInfo: info.AttachedInfo, // TODO } } @@ -56,7 +55,6 @@ func ServerGroupMemberToLocalGroupMember(info *sdkws.GroupMemberFullInfo) *model MuteEndTime: info.MuteEndTime, OperatorUserID: info.OperatorUserID, Ex: info.Ex, - //AttachedInfo: info.AttachedInfo, // todo } } @@ -76,22 +74,22 @@ func ServerGroupRequestToLocalGroupRequest(info *sdkws.GroupRequest) *model_stru UserID: info.UserInfo.UserID, Nickname: info.UserInfo.Nickname, UserFaceURL: info.UserInfo.FaceURL, - //Gender: info.UserInfo.Gender, - HandleResult: info.HandleResult, - ReqMsg: info.ReqMsg, - HandledMsg: info.HandleMsg, - ReqTime: info.ReqTime, - HandleUserID: info.HandleUserID, - HandledTime: info.HandleTime, - Ex: info.Ex, - //AttachedInfo: info.AttachedInfo, + HandleResult: info.HandleResult, + ReqMsg: info.ReqMsg, + HandledMsg: info.HandleMsg, + ReqTime: info.ReqTime, + HandleUserID: info.HandleUserID, + HandledTime: info.HandleTime, + Ex: info.Ex, JoinSource: info.JoinSource, InviterUserID: info.InviterUserID, } } -func ServerGroupRequestToLocalAdminGroupRequest(info *sdkws.GroupRequest) *model_struct.LocalAdminGroupRequest { - return &model_struct.LocalAdminGroupRequest{ - LocalGroupRequest: *ServerGroupRequestToLocalGroupRequest(info), +func ServerGroupRequestToLocalGroupRequestForNotification(groupInfo *sdkws.GroupInfo, groupRequest *sdkws.GroupRequest) *model_struct.LocalGroupRequest { + if groupInfo != nil { + groupRequest.GroupInfo = groupInfo } + return ServerGroupRequestToLocalGroupRequest(groupRequest) + } diff --git a/internal/group/filter.go b/internal/group/filter.go new file mode 100644 index 000000000..686e857ad --- /dev/null +++ b/internal/group/filter.go @@ -0,0 +1,52 @@ +package group + +import ( + "sync" + "time" + + "github.com/hashicorp/golang-lru/v2/simplelru" +) + +// NotificationFilter deduplicates events by UUID, ensuring that +// the same UUID is only processed once within the specified timeout. +type NotificationFilter struct { + lock sync.Mutex + data *simplelru.LRU[string, time.Time] + timeout time.Duration +} + +// NewNotificationFilter creates a NotificationFilter with the given +// capacity (size) and timeout duration. +func NewNotificationFilter(size int, timeout time.Duration) *NotificationFilter { + lru, err := simplelru.NewLRU[string, time.Time](size, nil) + if err != nil { + panic(err) + } + return &NotificationFilter{ + data: lru, + timeout: timeout, + } +} + +// ShouldExecute returns true if the UUID has not been processed +// within the timeout period. It also records the current time for this UUID. +// If the UUID was processed less than timeout ago, it returns false. +func (f *NotificationFilter) ShouldExecute(uuid string) bool { + f.lock.Lock() + defer f.lock.Unlock() + + now := time.Now() + if last, exists := f.data.Get(uuid); exists && now.Sub(last) <= f.timeout { + return false + } + f.data.Add(uuid, now) + return true +} + +// ExecuteIfNew calls fn only if the UUID has not been processed +// within the timeout period. Otherwise, it does nothing. +func (f *NotificationFilter) ExecuteIfNew(uuid string, fn func()) { + if f.ShouldExecute(uuid) { + fn() + } +} diff --git a/internal/group/full_sync.go b/internal/group/full_sync.go index b72db0cf5..db5d16bc4 100644 --- a/internal/group/full_sync.go +++ b/internal/group/full_sync.go @@ -18,100 +18,8 @@ import ( "context" "github.com/openimsdk/protocol/sdkws" - "github.com/openimsdk/tools/utils/datautil" ) -func (g *Group) SyncAllSelfGroupApplication(ctx context.Context) error { - if !g.groupRequestSyncerLock.TryLock() { - return nil - } - defer g.groupRequestSyncerLock.Unlock() - list, err := g.GetServerSelfGroupApplication(ctx) - if err != nil { - return err - } - localData, err := g.db.GetSendGroupApplication(ctx) - if err != nil { - return err - } - if err := g.groupRequestSyncer.Sync(ctx, datautil.Batch(ServerGroupRequestToLocalGroupRequest, list), localData, nil); err != nil { - return err - } - // todo - return nil -} - -func (g *Group) SyncAllSelfGroupApplicationWithoutNotice(ctx context.Context) error { - if !g.groupRequestSyncerLock.TryLock() { - return nil - } - defer g.groupRequestSyncerLock.Unlock() - list, err := g.GetServerSelfGroupApplication(ctx) - if err != nil { - return err - } - localData, err := g.db.GetSendGroupApplication(ctx) - if err != nil { - return err - } - if err := g.groupRequestSyncer.Sync(ctx, datautil.Batch(ServerGroupRequestToLocalGroupRequest, list), localData, nil, false, true); err != nil { - return err - } - return nil -} - -func (g *Group) SyncSelfGroupApplications(ctx context.Context, groupIDs ...string) error { - return g.SyncAllSelfGroupApplication(ctx) -} - -func (g *Group) SyncAllAdminGroupApplication(ctx context.Context) error { - if !g.groupAdminRequestSyncerLock.TryLock() { - return nil - } - defer g.groupAdminRequestSyncerLock.Unlock() - requests, err := g.GetServerAdminGroupApplicationList(ctx) - if err != nil { - return err - } - localData, err := g.db.GetAdminGroupApplication(ctx) - if err != nil { - return err - } - return g.groupAdminRequestSyncer.Sync(ctx, datautil.Batch(ServerGroupRequestToLocalAdminGroupRequest, requests), localData, nil) -} - -func (g *Group) SyncAllAdminGroupApplicationWithoutNotice(ctx context.Context) error { - if !g.groupAdminRequestSyncerLock.TryLock() { - return nil - } - defer g.groupAdminRequestSyncerLock.Unlock() - requests, err := g.GetServerAdminGroupApplicationList(ctx) - if err != nil { - return err - } - localData, err := g.db.GetAdminGroupApplication(ctx) - if err != nil { - return err - } - return g.groupAdminRequestSyncer.Sync(ctx, datautil.Batch(ServerGroupRequestToLocalAdminGroupRequest, requests), localData, nil, false, true) -} - -func (g *Group) SyncAdminGroupApplications(ctx context.Context, groupIDs ...string) error { - return g.SyncAllAdminGroupApplication(ctx) -} - func (g *Group) GetServerJoinGroup(ctx context.Context) ([]*sdkws.GroupInfo, error) { return g.getServerJoinGroup(ctx) } - -func (g *Group) GetServerAdminGroupApplicationList(ctx context.Context) ([]*sdkws.GroupRequest, error) { - return g.getServerAdminGroupApplicationList(ctx) -} - -func (g *Group) GetServerSelfGroupApplication(ctx context.Context) ([]*sdkws.GroupRequest, error) { - return g.getServerSelfGroupApplication(ctx) -} - -func (g *Group) GetDesignatedGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { - return g.getDesignatedGroupMembers(ctx, groupID, userIDs) -} diff --git a/internal/group/group.go b/internal/group/group.go index 37ca83b3c..d08289dc0 100644 --- a/internal/group/group.go +++ b/internal/group/group.go @@ -17,6 +17,7 @@ package group import ( "context" "sync" + "time" "github.com/openimsdk/openim-sdk-core/v3/open_im_sdk_callback" "github.com/openimsdk/openim-sdk-core/v3/pkg/api" @@ -37,14 +38,17 @@ import ( ) const ( - groupSyncLimit = 1047 - groupMemberSyncLimit = 1000 + groupSyncLimit = 1047 + groupMemberSyncLimit = 1000 + NotificationFilterCacheSize = 1024 + NotificationFilterTimeout = 10 * time.Second ) func NewGroup( conversationEventQueue *common.EventQueue) *Group { g := &Group{ conversationEventQueue: conversationEventQueue, + filter: NewNotificationFilter(NotificationFilterCacheSize, NotificationFilterTimeout), } g.initSyncer() g.groupMemberCache = cache.NewCache[string, *model_struct.LocalGroupMember]() @@ -52,24 +56,16 @@ func NewGroup( } type Group struct { - listener func() open_im_sdk_callback.OnGroupListener - loginUserID string - db db_interface.DataBase - groupSyncer *syncer.Syncer[*model_struct.LocalGroup, group.GetJoinedGroupListResp, string] - groupMemberSyncer *syncer.Syncer[*model_struct.LocalGroupMember, group.GetGroupMemberListResp, [2]string] - groupRequestSyncer *syncer.Syncer[*model_struct.LocalGroupRequest, syncer.NoResp, [2]string] - groupAdminRequestSyncer *syncer.Syncer[*model_struct.LocalAdminGroupRequest, syncer.NoResp, [2]string] - + listener func() open_im_sdk_callback.OnGroupListener + loginUserID string + db db_interface.DataBase + groupSyncer *syncer.Syncer[*model_struct.LocalGroup, group.GetJoinedGroupListResp, string] + groupMemberSyncer *syncer.Syncer[*model_struct.LocalGroupMember, group.GetGroupMemberListResp, [2]string] conversationEventQueue *common.EventQueue - // memberSyncMutex sync.RWMutex - - groupSyncMutex sync.Mutex - listenerForService open_im_sdk_callback.OnListenerForService - - groupMemberCache *cache.Cache[string, *model_struct.LocalGroupMember] - - groupRequestSyncerLock sync.Mutex - groupAdminRequestSyncerLock sync.Mutex + groupSyncMutex sync.Mutex + listenerForService open_im_sdk_callback.OnListenerForService + groupMemberCache *cache.Cache[string, *model_struct.LocalGroupMember] + filter *NotificationFilter } func (g *Group) initSyncer() { @@ -213,56 +209,6 @@ func (g *Group) initSyncer() { syncer.WithFullSyncLimit[*model_struct.LocalGroupMember, group.GetGroupMemberListResp, [2]string](groupMemberSyncLimit), ) - g.groupRequestSyncer = syncer.New[*model_struct.LocalGroupRequest, syncer.NoResp, [2]string](func(ctx context.Context, value *model_struct.LocalGroupRequest) error { - return g.db.InsertGroupRequest(ctx, value) - }, func(ctx context.Context, value *model_struct.LocalGroupRequest) error { - return g.db.DeleteGroupRequest(ctx, value.GroupID, value.UserID) - }, func(ctx context.Context, server, local *model_struct.LocalGroupRequest) error { - return g.db.UpdateGroupRequest(ctx, server) - }, func(value *model_struct.LocalGroupRequest) [2]string { - return [...]string{value.GroupID, value.UserID} - }, nil, func(ctx context.Context, state int, server, local *model_struct.LocalGroupRequest) error { - switch state { - case syncer.Insert: - g.listener().OnGroupApplicationAdded(utils.StructToJsonString(server)) - case syncer.Update: - switch server.HandleResult { - case constant.FriendResponseAgree: - g.listener().OnGroupApplicationAccepted(utils.StructToJsonString(server)) - case constant.FriendResponseRefuse: - g.listener().OnGroupApplicationRejected(utils.StructToJsonString(server)) - default: - g.listener().OnGroupApplicationAdded(utils.StructToJsonString(server)) - } - } - return nil - }) - - g.groupAdminRequestSyncer = syncer.New[*model_struct.LocalAdminGroupRequest, syncer.NoResp, [2]string](func(ctx context.Context, value *model_struct.LocalAdminGroupRequest) error { - return g.db.InsertAdminGroupRequest(ctx, value) - }, func(ctx context.Context, value *model_struct.LocalAdminGroupRequest) error { - return g.db.DeleteAdminGroupRequest(ctx, value.GroupID, value.UserID) - }, func(ctx context.Context, server, local *model_struct.LocalAdminGroupRequest) error { - return g.db.UpdateAdminGroupRequest(ctx, server) - }, func(value *model_struct.LocalAdminGroupRequest) [2]string { - return [...]string{value.GroupID, value.UserID} - }, nil, func(ctx context.Context, state int, server, local *model_struct.LocalAdminGroupRequest) error { - switch state { - case syncer.Insert: - g.listener().OnGroupApplicationAdded(utils.StructToJsonString(server)) - case syncer.Update: - switch server.HandleResult { - case constant.FriendResponseAgree: - g.listener().OnGroupApplicationAccepted(utils.StructToJsonString(server)) - case constant.FriendResponseRefuse: - g.listener().OnGroupApplicationRejected(utils.StructToJsonString(server)) - default: - g.listener().OnGroupApplicationAdded(utils.StructToJsonString(server)) - } - } - return nil - }) - } func (g *Group) SetGroupListener(listener func() open_im_sdk_callback.OnGroupListener) { @@ -306,10 +252,6 @@ func (g *Group) FetchGroupOrError(ctx context.Context, groupID string) (*model_s return groups[0], nil } -func (g *Group) delLocalGroupRequest(ctx context.Context, groupID, userID string) error { - return g.db.DeleteGroupRequest(ctx, groupID, userID) -} - // SetDataBase sets the DataBase field in Group struct func (g *Group) SetDataBase(db db_interface.DataBase) { g.db = db diff --git a/internal/group/notification.go b/internal/group/notification.go index 1c82c27d1..d9931dd9e 100644 --- a/internal/group/notification.go +++ b/internal/group/notification.go @@ -45,13 +45,9 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { return err } - switch detail.ReceiverAs { - case constant.ApplicantReceiver: - return g.SyncAllSelfGroupApplication(ctx) - case constant.AdminReceiver: - return g.SyncAdminGroupApplications(ctx, detail.Group.GroupID) - default: - return errs.New(fmt.Sprintf("GroupApplicationAcceptedNotification ReceiverAs unknown %d", detail.ReceiverAs)).Wrap() + if g.filter.ShouldExecute(detail.Uuid) { + g.listener().OnGroupApplicationAccepted(utils.StructToJsonString( + ServerGroupRequestToLocalGroupRequestForNotification(detail.GetGroup(), detail.GetRequest()))) } case constant.GroupApplicationRejectedNotification: // 1506 @@ -59,15 +55,19 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { return err } - switch detail.ReceiverAs { - case 0: - return g.SyncAllSelfGroupApplication(ctx) - case 1: - return g.SyncAdminGroupApplications(ctx, detail.Group.GroupID) - default: - return errs.New(fmt.Sprintf("GroupApplicationRejectedNotification ReceiverAs unknown %d", detail.ReceiverAs)).Wrap() + if g.filter.ShouldExecute(detail.Uuid) { + g.listener().OnGroupApplicationRejected(utils.StructToJsonString( + ServerGroupRequestToLocalGroupRequestForNotification(detail.GetGroup(), detail.GetRequest()))) + } + case constant.JoinGroupApplicationNotification: // 1503 + var detail sdkws.JoinGroupApplicationTips + if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { + return err + } + if g.filter.ShouldExecute(detail.Uuid) { + g.listener().OnGroupMemberAdded(utils.StructToJsonString( + ServerGroupRequestToLocalGroupRequestForNotification(detail.GetGroup(), detail.GetRequest()))) } - default: g.groupSyncMutex.Lock() defer g.groupSyncMutex.Unlock() @@ -90,16 +90,7 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { } return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, nil, nil, nil, detail.Group, groupSortIDUnchanged, detail.GroupMemberVersion, detail.GroupMemberVersionID) - case constant.JoinGroupApplicationNotification: // 1503 - var detail sdkws.JoinGroupApplicationTips - if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { - return err - } - if detail.Applicant.UserID == g.loginUserID { - return g.SyncSelfGroupApplications(ctx, detail.Group.GroupID) - } else { - return g.SyncAdminGroupApplications(ctx, detail.Group.GroupID) - } + case constant.MemberQuitNotification: // 1504 var detail sdkws.MemberQuitTips if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { @@ -119,11 +110,6 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if detail.Group == nil { return errs.New(fmt.Sprintf("group is nil, groupID: %s", detail.Group.GroupID)).Wrap() } - if detail.NewGroupOwner.RoleLevel < constant.GroupAdmin && detail.OldGroupOwner == g.loginUserID { - if err := g.delLocalGroupRequest(ctx, detail.Group.GroupID, g.loginUserID); err != nil { - return err - } - } return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, nil, []*sdkws.GroupMemberFullInfo{detail.NewGroupOwner, detail.OldGroupOwnerInfo}, nil, detail.Group, groupSortIDChanged, detail.GroupMemberVersion, detail.GroupMemberVersionID) @@ -140,9 +126,6 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { } } if self { - if err := g.delLocalGroupRequest(ctx, detail.Group.GroupID, g.loginUserID); err != nil { - return err - } return g.IncrSyncJoinGroup(ctx) } else { return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, detail.KickedUserList, nil, @@ -223,11 +206,6 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { return err } - if detail.ChangedUser.RoleLevel < constant.GroupAdmin && detail.ChangedUser.UserID == g.loginUserID { - if err := g.delLocalGroupRequest(ctx, detail.Group.GroupID, g.loginUserID); err != nil { - return err - } - } return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, nil, []*sdkws.GroupMemberFullInfo{detail.ChangedUser}, nil, nil, detail.GroupSortVersion, detail.GroupMemberVersion, detail.GroupMemberVersionID) @@ -244,11 +222,6 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { return err } - if detail.ChangedUser.UserID == g.loginUserID { - if err := g.delLocalGroupRequest(ctx, detail.Group.GroupID, g.loginUserID); err != nil { - return err - } - } return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, nil, []*sdkws.GroupMemberFullInfo{detail.ChangedUser}, nil, nil, detail.GroupSortVersion, detail.GroupMemberVersion, detail.GroupMemberVersionID) @@ -270,4 +243,5 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { return errs.New("unknown tips type", "contentType", msg.ContentType).Wrap() } } + return nil } diff --git a/internal/group/server_api.go b/internal/group/server_api.go index bcff10add..c9df98108 100644 --- a/internal/group/server_api.go +++ b/internal/group/server_api.go @@ -78,8 +78,10 @@ func (g *Group) getDesignatedGroupMembers(ctx context.Context, groupID string, u return api.ExtractField(ctx, api.GetGroupMembersInfo.Invoke, req, (*group.GetGroupMembersInfoResp).GetMembers) } -func (g *Group) getServerSelfGroupApplication(ctx context.Context) ([]*sdkws.GroupRequest, error) { - req := &group.GetUserReqApplicationListReq{UserID: g.loginUserID, Pagination: &sdkws.RequestPagination{}} +func (g *Group) getServerSelfGroupApplication(ctx context.Context, groupIDs []string, + handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.GroupRequest, error) { + req := &group.GetUserReqApplicationListReq{UserID: g.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, + GroupIDs: groupIDs, HandleResults: handleResults} return api.Page(ctx, req, api.GetSendGroupApplicationList.Invoke, (*group.GetUserReqApplicationListResp).GetGroupRequests) } @@ -88,8 +90,10 @@ func (g *Group) getServerJoinGroup(ctx context.Context) ([]*sdkws.GroupInfo, err return api.Page(ctx, req, api.GetJoinedGroupList.Invoke, (*group.GetJoinedGroupListResp).GetGroups) } -func (g *Group) getServerAdminGroupApplicationList(ctx context.Context) ([]*sdkws.GroupRequest, error) { - req := &group.GetGroupApplicationListReq{FromUserID: g.loginUserID, Pagination: &sdkws.RequestPagination{}} +func (g *Group) getServerAdminGroupApplicationList(ctx context.Context, groupIDs []string, + handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.GroupRequest, error) { + req := &group.GetGroupApplicationListReq{FromUserID: g.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, + GroupIDs: groupIDs, HandleResults: handleResults} return api.Page(ctx, req, api.GetRecvGroupApplicationList.Invoke, (*group.GetGroupApplicationListResp).GetGroupRequests) } diff --git a/internal/interaction/msg_sync.go b/internal/interaction/msg_sync.go index a98cd8c98..f31acbd78 100644 --- a/internal/interaction/msg_sync.go +++ b/internal/interaction/msg_sync.go @@ -416,6 +416,11 @@ func (m *MsgSyncer) pushTriggerAndSync(ctx context.Context, pushMessages map[str // Called after successful reconnection to synchronize the latest message func (m *MsgSyncer) doConnected(ctx context.Context) { reinstalled := m.reinstalled + if reinstalled { + common.DispatchSyncFlagWithMeta(ctx, constant.AppDataSyncBegin, nil, m.conversationEventQueue) + } else { + common.DispatchSyncFlagWithMeta(ctx, constant.MsgSyncBegin, nil, m.conversationEventQueue) + } var resp sdkws.GetMaxSeqResp if err := m.longConnMgr.SendReqWaitResp(ctx, &sdkws.GetMaxSeqReq{UserID: m.loginUserID}, constant.GetNewestSeq, &resp); err != nil { log.ZError(ctx, "get max seq error", err) @@ -431,15 +436,15 @@ func (m *MsgSyncer) doConnected(ctx context.Context) { convCount := len(needSyncAllSeqMap) if convCount == 0 { - log.ZInfo(ctx, "no conversations need sync") - return + log.ZInfo(ctx, "no conversations messages need to sync") } // In cases where there is no uninstall and reinstall, // the amount of conversation data to be synchronized in a single operation is too large if len(needSyncAllSeqMap) >= maxConversations { - log.ZDebug(ctx, "large conversations to sync", nil, "length", len(needSyncAllSeqMap)) + log.ZDebug(ctx, "large conversations to sync", "length", len(needSyncAllSeqMap)) m.isLargeDataSync = true + common.DispatchSyncFlagWithMeta(ctx, constant.LargeDataSyncBegin, nil, m.conversationEventQueue) } maxSeqs, sortConversationList, err := m.SyncAndSortConversations(ctx, reinstalled) @@ -447,13 +452,13 @@ func (m *MsgSyncer) doConnected(ctx context.Context) { log.ZError(ctx, "SyncAndSortConversations err", err) } if reinstalled { - common.DispatchSyncFlagWithMeta(ctx, constant.AppDataSyncBegin, maxSeqs, m.conversationEventQueue) + common.DispatchSyncFlagWithMeta(ctx, constant.AppDataSyncData, maxSeqs, m.conversationEventQueue) } else { if m.isLargeDataSync { log.ZWarn(ctx, "too many conversations to sync", nil, "maxConversations", maxConversations) - common.DispatchSyncFlagWithMeta(ctx, constant.LargeDataSyncBegin, maxSeqs, m.conversationEventQueue) + common.DispatchSyncFlagWithMeta(ctx, constant.LargeDataSyncData, maxSeqs, m.conversationEventQueue) } else { - common.DispatchSyncFlagWithMeta(ctx, constant.MsgSyncBegin, maxSeqs, m.conversationEventQueue) + common.DispatchSyncFlagWithMeta(ctx, constant.MsgSyncData, maxSeqs, m.conversationEventQueue) } } @@ -488,7 +493,7 @@ func (m *MsgSyncer) handleMessage(ctx context.Context, batchID int, needSyncTopS } } else { if m.isLargeDataSync { - log.ZWarn(ctx, "handleMessage large conversations to sync", nil, "length", len(needSyncTopSeqMap), "isFirst", isFirst, "maxConversations", maxConversations) + log.ZDebug(ctx, "handleMessage large conversations to sync", "length", len(needSyncTopSeqMap), "isFirst", isFirst, "maxConversations", maxConversations) _ = m.syncAndTriggerReinstallMsgs(ctx, needSyncTopSeqMap, isFirst, connectPullNums) if isFirst { common.DispatchSyncFlag(ctx, constant.LargeDataSyncEnd, m.conversationEventQueue) diff --git a/internal/relation/api.go b/internal/relation/api.go index 0645f73a5..5d5c5971e 100644 --- a/internal/relation/api.go +++ b/internal/relation/api.go @@ -32,7 +32,7 @@ func (r *Relation) GetSpecifiedFriendsInfo(ctx context.Context, friendUserIDList return localFriends, true, err }, func(ctx context.Context, userIDs []string) ([]*model_struct.LocalFriend, error) { - serverFriend, err := r.GetDesignatedFriends(ctx, userIDs) + serverFriend, err := r.getDesignatedFriends(ctx, userIDs) if err != nil { return nil, err } @@ -69,21 +69,23 @@ func (r *Relation) GetSpecifiedFriendsInfo(ctx context.Context, friendUserIDList } func (r *Relation) AddFriend(ctx context.Context, req *relation.ApplyToAddFriendReq) error { - if err := r.addFriend(ctx, req); err != nil { - return err - } - r.relationSyncMutex.Lock() - defer r.relationSyncMutex.Unlock() - - return r.SyncAllSelfFriendApplication(ctx) + return r.addFriend(ctx, req) } -func (r *Relation) GetFriendApplicationListAsRecipient(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) { - return r.db.GetRecvFriendApplication(ctx) +func (r *Relation) GetFriendApplicationListAsRecipient(ctx context.Context, req *sdk.GetFriendApplicationListAsRecipientReq) ([]*model_struct.LocalFriendRequest, error) { + friendRequests, err := r.getRecvFriendApplicationList(ctx, req.HandleResults, req.Offset/req.Count+1, req.Count) + if err != nil { + return nil, err + } + return datautil.Batch(ServerFriendRequestToLocalFriendRequest, friendRequests), nil } -func (r *Relation) GetFriendApplicationListAsApplicant(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) { - return r.db.GetSendFriendApplication(ctx) +func (r *Relation) GetFriendApplicationListAsApplicant(ctx context.Context, req *sdk.GetFriendApplicationListAsApplicantReq) ([]*model_struct.LocalFriendRequest, error) { + friendRequests, err := r.getSelfFriendApplicationList(ctx, req.Offset/req.Count+1, req.Count) + if err != nil { + return nil, err + } + return datautil.Batch(ServerFriendRequestToLocalFriendRequest, friendRequests), nil } func (r *Relation) AcceptFriendApplication(ctx context.Context, userIDHandleMsg *sdk.ProcessFriendApplicationParams) error { @@ -104,9 +106,7 @@ func (r *Relation) RespondFriendApply(ctx context.Context, req *relation.Respond if req.HandleResult == constant.FriendResponseAgree { _ = r.IncrSyncFriends(ctx) } - _ = r.SyncAllFriendApplication(ctx) return nil - // return r.SyncFriendApplication(ctx) } func (r *Relation) CheckFriend(ctx context.Context, friendUserIDList []string) ([]*server_api_params.UserIDResult, error) { @@ -200,7 +200,7 @@ func (r *Relation) GetFriendListPage(ctx context.Context, offset, count int32, f return localFriendList, true, err }, func(ctx context.Context, userIDs []string) ([]*model_struct.LocalFriend, error) { - serverFriend, err := r.GetDesignatedFriends(ctx, userIDs) + serverFriend, err := r.getDesignatedFriends(ctx, userIDs) if err != nil { return nil, err } diff --git a/internal/relation/conversion.go b/internal/relation/conversion.go index de6098197..02a078940 100644 --- a/internal/relation/conversion.go +++ b/internal/relation/conversion.go @@ -7,14 +7,12 @@ import ( func ServerFriendRequestToLocalFriendRequest(info *sdkws.FriendRequest) *model_struct.LocalFriendRequest { return &model_struct.LocalFriendRequest{ - FromUserID: info.FromUserID, - FromNickname: info.FromNickname, - FromFaceURL: info.FromFaceURL, - //FromGender: info.FromGender, - ToUserID: info.ToUserID, - ToNickname: info.ToNickname, - ToFaceURL: info.ToFaceURL, - //ToGender: info.ToGender, + FromUserID: info.FromUserID, + FromNickname: info.FromNickname, + FromFaceURL: info.FromFaceURL, + ToUserID: info.ToUserID, + ToNickname: info.ToNickname, + ToFaceURL: info.ToFaceURL, HandleResult: info.HandleResult, ReqMsg: info.ReqMsg, CreateTime: info.CreateTime, @@ -22,7 +20,6 @@ func ServerFriendRequestToLocalFriendRequest(info *sdkws.FriendRequest) *model_s HandleMsg: info.HandleMsg, HandleTime: info.HandleTime, Ex: info.Ex, - //AttachedInfo: info.AttachedInfo, } } @@ -37,8 +34,7 @@ func ServerFriendToLocalFriend(info *sdkws.FriendInfo) *model_struct.LocalFriend Nickname: info.FriendUser.Nickname, FaceURL: info.FriendUser.FaceURL, Ex: info.Ex, - //AttachedInfo: info.FriendUser.AttachedInfo, - IsPinned: info.IsPinned, + IsPinned: info.IsPinned, } } @@ -52,6 +48,5 @@ func ServerBlackToLocalBlack(info *sdkws.BlackInfo) *model_struct.LocalBlack { Nickname: info.BlackUserInfo.Nickname, FaceURL: info.BlackUserInfo.FaceURL, Ex: info.Ex, - //AttachedInfo: info.FriendUser.AttachedInfo, } } diff --git a/internal/relation/notification.go b/internal/relation/notification.go index a42e71679..02f17dded 100644 --- a/internal/relation/notification.go +++ b/internal/relation/notification.go @@ -26,30 +26,21 @@ func (r *Relation) doNotification(ctx context.Context, msg *sdkws.MsgData) error if err := utils.UnmarshalNotificationElem(msg.Content, &tips); err != nil { return err } - return r.SyncBothFriendRequest(ctx, - tips.FromToUserID.FromUserID, tips.FromToUserID.ToUserID) + r.friendshipListener.OnFriendApplicationAdded(*ServerFriendRequestToLocalFriendRequest(tips.Request)) case constant.FriendApplicationApprovedNotification: var tips sdkws.FriendApplicationApprovedTips err := utils.UnmarshalNotificationElem(msg.Content, &tips) if err != nil { return err } - - if tips.FromToUserID.FromUserID == r.loginUserID { - err = r.IncrSyncFriends(ctx) - } else if tips.FromToUserID.ToUserID == r.loginUserID { - err = r.IncrSyncFriends(ctx) - } - if err != nil { - return err - } - return r.SyncBothFriendRequest(ctx, tips.FromToUserID.FromUserID, tips.FromToUserID.ToUserID) + r.friendshipListener.OnFriendApplicationAccepted(*ServerFriendRequestToLocalFriendRequest(tips.Request)) + return r.IncrSyncFriends(ctx) case constant.FriendApplicationRejectedNotification: var tips sdkws.FriendApplicationRejectedTips if err := utils.UnmarshalNotificationElem(msg.Content, &tips); err != nil { return err } - return r.SyncBothFriendRequest(ctx, tips.FromToUserID.FromUserID, tips.FromToUserID.ToUserID) + r.friendshipListener.OnFriendApplicationRejected(*ServerFriendRequestToLocalFriendRequest(tips.Request)) case constant.FriendAddedNotification: var tips sdkws.FriendAddedTips if err := utils.UnmarshalNotificationElem(msg.Content, &tips); err != nil { diff --git a/internal/relation/relation.go b/internal/relation/relation.go index f03929f6f..dcd9dda33 100644 --- a/internal/relation/relation.go +++ b/internal/relation/relation.go @@ -37,14 +37,9 @@ type Relation struct { user *user.User friendSyncer *syncer.Syncer[*model_struct.LocalFriend, relation.GetPaginationFriendsResp, [2]string] blackSyncer *syncer.Syncer[*model_struct.LocalBlack, syncer.NoResp, [2]string] - requestRecvSyncer *syncer.Syncer[*model_struct.LocalFriendRequest, syncer.NoResp, [2]string] - requestSendSyncer *syncer.Syncer[*model_struct.LocalFriendRequest, syncer.NoResp, [2]string] conversationEventQueue *common.EventQueue listenerForService open_im_sdk_callback.OnListenerForService relationSyncMutex sync.Mutex - - requestRecvSyncerLock sync.Mutex - requestSendSyncerLock sync.Mutex } func (r *Relation) initSyncer() { @@ -153,56 +148,6 @@ func (r *Relation) initSyncer() { } return nil }) - r.requestRecvSyncer = syncer.New[*model_struct.LocalFriendRequest, syncer.NoResp, [2]string](func(ctx context.Context, value *model_struct.LocalFriendRequest) error { - return r.db.InsertFriendRequest(ctx, value) - }, func(ctx context.Context, value *model_struct.LocalFriendRequest) error { - return r.db.DeleteFriendRequestBothUserID(ctx, value.FromUserID, value.ToUserID) - }, func(ctx context.Context, server *model_struct.LocalFriendRequest, local *model_struct.LocalFriendRequest) error { - return r.db.UpdateFriendRequest(ctx, server) - }, func(value *model_struct.LocalFriendRequest) [2]string { - return [...]string{value.FromUserID, value.ToUserID} - }, nil, func(ctx context.Context, state int, server, local *model_struct.LocalFriendRequest) error { - switch state { - case syncer.Insert: - r.friendshipListener.OnFriendApplicationAdded(*server) - case syncer.Delete: - r.friendshipListener.OnFriendApplicationDeleted(*local) - case syncer.Update: - switch server.HandleResult { - case constant.FriendResponseAgree: - r.friendshipListener.OnFriendApplicationAccepted(*server) - case constant.FriendResponseRefuse: - r.friendshipListener.OnFriendApplicationRejected(*server) - case constant.FriendResponseDefault: - r.friendshipListener.OnFriendApplicationAdded(*server) - } - } - return nil - }) - r.requestSendSyncer = syncer.New[*model_struct.LocalFriendRequest, syncer.NoResp, [2]string](func(ctx context.Context, value *model_struct.LocalFriendRequest) error { - return r.db.InsertFriendRequest(ctx, value) - }, func(ctx context.Context, value *model_struct.LocalFriendRequest) error { - return r.db.DeleteFriendRequestBothUserID(ctx, value.FromUserID, value.ToUserID) - }, func(ctx context.Context, server *model_struct.LocalFriendRequest, local *model_struct.LocalFriendRequest) error { - return r.db.UpdateFriendRequest(ctx, server) - }, func(value *model_struct.LocalFriendRequest) [2]string { - return [...]string{value.FromUserID, value.ToUserID} - }, nil, func(ctx context.Context, state int, server, local *model_struct.LocalFriendRequest) error { - switch state { - case syncer.Insert: - r.friendshipListener.OnFriendApplicationAdded(*server) - case syncer.Delete: - r.friendshipListener.OnFriendApplicationDeleted(*local) - case syncer.Update: - switch server.HandleResult { - case constant.FriendResponseAgree: - r.friendshipListener.OnFriendApplicationAccepted(*server) - case constant.FriendResponseRefuse: - r.friendshipListener.OnFriendApplicationRejected(*server) - } - } - return nil - }) } func (r *Relation) Db() db_interface.DataBase { diff --git a/internal/relation/server_api.go b/internal/relation/server_api.go index 6f520368e..0d3cbfeb8 100644 --- a/internal/relation/server_api.go +++ b/internal/relation/server_api.go @@ -12,12 +12,15 @@ func (r *Relation) getDesignatedFriendsApply(ctx context.Context, req *relation. return api.ExtractField(ctx, api.GetDesignatedFriendsApply.Invoke, req, (*relation.GetDesignatedFriendsApplyResp).GetFriendRequests) } -func (r *Relation) getSelfFriendApplicationList(ctx context.Context, req *relation.GetPaginationFriendsApplyFromReq) ([]*sdkws.FriendRequest, error) { +func (r *Relation) getSelfFriendApplicationList(ctx context.Context, pageNumber, showNumber int32) ([]*sdkws.FriendRequest, error) { + req := &relation.GetPaginationFriendsApplyFromReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}} return api.Page(ctx, req, api.GetSelfFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyFromResp).GetFriendRequests) } -func (r *Relation) getFriendApplicationList(ctx context.Context, req *relation.GetPaginationFriendsApplyToReq) ([]*sdkws.FriendRequest, error) { - return api.Page(ctx, req, api.GetFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyToResp).GetFriendRequests) +func (r *Relation) getRecvFriendApplicationList(ctx context.Context, handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.FriendRequest, error) { + req := &relation.GetPaginationFriendsApplyToReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, + HandleResults: handleResults} + return api.Page(ctx, req, api.GetRecvFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyToResp).GetFriendRequests) } func (r *Relation) getBlackList(ctx context.Context) ([]*sdkws.BlackInfo, error) { diff --git a/internal/relation/sync.go b/internal/relation/sync.go index 07f47a2df..273711b4c 100644 --- a/internal/relation/sync.go +++ b/internal/relation/sync.go @@ -5,109 +5,9 @@ import ( "github.com/openimsdk/tools/utils/datautil" - "github.com/openimsdk/protocol/relation" - "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/log" ) -func (r *Relation) SyncBothFriendRequest(ctx context.Context, fromUserID, toUserID string) error { - if toUserID == r.loginUserID { - if !r.requestRecvSyncerLock.TryLock() { - return nil - } - defer r.requestRecvSyncerLock.Unlock() - } else { - if !r.requestSendSyncerLock.TryLock() { - return nil - } - defer r.requestSendSyncerLock.Unlock() - } - req := &relation.GetDesignatedFriendsApplyReq{FromUserID: fromUserID, ToUserID: toUserID} - friendRequests, err := r.getDesignatedFriendsApply(ctx, req) - if err != nil { - return err - } - localData, err := r.db.GetBothFriendReq(ctx, fromUserID, toUserID) - if err != nil { - return err - } - if toUserID == r.loginUserID { - return r.requestRecvSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, friendRequests), localData, nil) - } else if fromUserID == r.loginUserID { - return r.requestSendSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, friendRequests), localData, nil) - } - return nil -} - -// SyncAllSelfFriendApplication send -func (r *Relation) SyncAllSelfFriendApplication(ctx context.Context) error { - if !r.requestSendSyncerLock.TryLock() { - return nil - } - defer r.requestSendSyncerLock.Unlock() - req := &relation.GetPaginationFriendsApplyFromReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{}} - requests, err := r.getSelfFriendApplicationList(ctx, req) - if err != nil { - return err - } - localData, err := r.db.GetSendFriendApplication(ctx) - if err != nil { - return err - } - return r.requestSendSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, requests), localData, nil) -} - -func (r *Relation) SyncAllSelfFriendApplicationWithoutNotice(ctx context.Context) error { - if !r.requestSendSyncerLock.TryLock() { - return nil - } - defer r.requestSendSyncerLock.Unlock() - req := &relation.GetPaginationFriendsApplyFromReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{}} - requests, err := r.getSelfFriendApplicationList(ctx, req) - if err != nil { - return err - } - localData, err := r.db.GetSendFriendApplication(ctx) - if err != nil { - return err - } - return r.requestSendSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, requests), localData, nil, false, true) -} - -// SyncAllFriendApplication recv -func (r *Relation) SyncAllFriendApplication(ctx context.Context) error { - if !r.requestRecvSyncerLock.TryLock() { - return nil - } - defer r.requestRecvSyncerLock.Unlock() - req := &relation.GetPaginationFriendsApplyToReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{}} - requests, err := r.getFriendApplicationList(ctx, req) - if err != nil { - return err - } - localData, err := r.db.GetRecvFriendApplication(ctx) - if err != nil { - return err - } - return r.requestRecvSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, requests), localData, nil) -} -func (r *Relation) SyncAllFriendApplicationWithoutNotice(ctx context.Context) error { - if !r.requestRecvSyncerLock.TryLock() { - return nil - } - defer r.requestRecvSyncerLock.Unlock() - req := &relation.GetPaginationFriendsApplyToReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{}} - requests, err := r.getFriendApplicationList(ctx, req) - if err != nil { - return err - } - localData, err := r.db.GetRecvFriendApplication(ctx) - if err != nil { - return err - } - return r.requestRecvSyncer.Sync(ctx, datautil.Batch(ServerFriendRequestToLocalFriendRequest, requests), localData, nil, false, true) -} - func (r *Relation) SyncAllBlackList(ctx context.Context) error { serverData, err := r.getBlackList(ctx) if err != nil { @@ -135,7 +35,3 @@ func (r *Relation) SyncAllBlackListWithoutNotice(ctx context.Context) error { log.ZDebug(ctx, "black from local", "data", localData) return r.blackSyncer.Sync(ctx, datautil.Batch(ServerBlackToLocalBlack, serverData), localData, nil, false, true) } - -func (r *Relation) GetDesignatedFriends(ctx context.Context, friendIDs []string) ([]*sdkws.FriendInfo, error) { - return r.getDesignatedFriends(ctx, friendIDs) -} diff --git a/internal/user/full_sync.go b/internal/user/full_sync.go index 3d9fd8bd7..fac252cfc 100644 --- a/internal/user/full_sync.go +++ b/internal/user/full_sync.go @@ -2,7 +2,6 @@ package user import ( "context" - "errors" "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" "github.com/openimsdk/tools/errs" @@ -32,8 +31,8 @@ func (u *User) SyncLoginUserInfoWithoutNotice(ctx context.Context) error { return err } localUser, err := u.GetLoginUser(ctx, u.loginUserID) - if err != nil && errors.Is(errs.Unwrap(err), errs.ErrRecordNotFound) { - log.ZError(ctx, "SyncLoginUserInfo", err) + if err != nil && (!errs.ErrRecordNotFound.Is(errs.Unwrap(err))) { + return err } var localUsers []*model_struct.LocalUser if err == nil { diff --git a/open_im_sdk/init_login.go b/open_im_sdk/init_login.go index 5527009fc..e8692f135 100644 --- a/open_im_sdk/init_login.go +++ b/open_im_sdk/init_login.go @@ -80,6 +80,13 @@ func UnInitSDK(_ string) { IMUserContext.UnInitSDK() } +func GetLoginUserID() string { + if IMUserContext == nil { + return "" + } + return IMUserContext.GetLoginUserID() +} + func Login(callback open_im_sdk_callback.Base, operationID string, userID, token string) { call(callback, operationID, IMUserContext.Login, userID, token) } diff --git a/open_im_sdk/userRelated.go b/open_im_sdk/userRelated.go index 6acc0751d..0487bc4f2 100644 --- a/open_im_sdk/userRelated.go +++ b/open_im_sdk/userRelated.go @@ -265,6 +265,10 @@ func (u *UserContext) SetCustomBusinessListener(listener open_im_sdk_callback.On u.businessListener = listener } +func (u *UserContext) GetLoginUserID() string { + return u.loginUserID +} + func (u *UserContext) logoutListener(ctx context.Context) { defer func() { if r := recover(); r != nil { diff --git a/pkg/api/api.go b/pkg/api/api.go index cf2f4afb6..af8825d87 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -26,8 +26,9 @@ var ( var ( AddFriend = newApi[relation.ApplyToAddFriendReq, relation.ApplyToAddFriendResp]("/friend/add_friend") DeleteFriend = newApi[relation.DeleteFriendReq, relation.DeleteFriendResp]("/friend/delete_friend") - GetFriendApplicationList = newApi[relation.GetPaginationFriendsApplyToReq, relation.GetPaginationFriendsApplyToResp]("/friend/get_friend_apply_list") + GetRecvFriendApplicationList = newApi[relation.GetPaginationFriendsApplyToReq, relation.GetPaginationFriendsApplyToResp]("/friend/get_friend_apply_list") GetSelfFriendApplicationList = newApi[relation.GetPaginationFriendsApplyFromReq, relation.GetPaginationFriendsApplyFromResp]("/friend/get_self_friend_apply_list") + GetSelfUnhandledApplyCount = newApi[relation.GetSelfUnhandledApplyCountReq, relation.GetSelfUnhandledApplyCountResp]("/friend/get_self_unhandled_apply_count") ImportFriendList = newApi[relation.ImportFriendReq, relation.ImportFriendResp]("/friend/import_friend") GetDesignatedFriendsApply = newApi[relation.GetDesignatedFriendsApplyReq, relation.GetDesignatedFriendsApplyResp]("/friend/get_designated_friend_apply") GetFriendList = newApi[relation.GetPaginationFriendsReq, relation.GetPaginationFriendsResp]("/friend/get_friend_list") @@ -55,30 +56,31 @@ var ( ) var ( - CreateGroup = newApi[group.CreateGroupReq, group.CreateGroupResp]("/group/create_group") - SetGroupInfoEx = newApi[group.SetGroupInfoExReq, group.SetGroupInfoExResp]("/group/set_group_info_ex") - JoinGroup = newApi[group.JoinGroupReq, group.JoinGroupResp]("/group/join_group") - QuitGroup = newApi[group.QuitGroupReq, group.QuitGroupResp]("/group/quit_group") - GetGroupsInfo = newApi[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") - GetGroupMemberList = newApi[group.GetGroupMemberListReq, group.GetGroupMemberListResp]("/group/get_group_member_list") - GetGroupMembersInfo = newApi[group.GetGroupMembersInfoReq, group.GetGroupMembersInfoResp]("/group/get_group_members_info") - InviteUserToGroup = newApi[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") - GetJoinedGroupList = newApi[group.GetJoinedGroupListReq, group.GetJoinedGroupListResp]("/group/get_joined_group_list") - KickGroupMember = newApi[group.KickGroupMemberReq, group.KickGroupMemberResp]("/group/kick_group") - TransferGroup = newApi[group.TransferGroupOwnerReq, group.TransferGroupOwnerResp]("/group/transfer_group") - GetRecvGroupApplicationList = newApi[group.GetGroupApplicationListReq, group.GetGroupApplicationListResp]("/group/get_recv_group_applicationList") - GetSendGroupApplicationList = newApi[group.GetUserReqApplicationListReq, group.GetUserReqApplicationListResp]("/group/get_user_req_group_applicationList") - AcceptGroupApplication = newApi[group.GroupApplicationResponseReq, group.GroupApplicationResponseResp]("/group/group_application_response") - DismissGroup = newApi[group.DismissGroupReq, group.DismissGroupResp]("/group/dismiss_group") - MuteGroupMember = newApi[group.MuteGroupMemberReq, group.MuteGroupMemberResp]("/group/mute_group_member") - CancelMuteGroupMember = newApi[group.CancelMuteGroupMemberReq, group.CancelMuteGroupMemberResp]("/group/cancel_mute_group_member") - MuteGroup = newApi[group.MuteGroupReq, group.MuteGroupResp]("/group/mute_group") - CancelMuteGroup = newApi[group.CancelMuteGroupReq, group.CancelMuteGroupResp]("/group/cancel_mute_group") - SetGroupMemberInfo = newApi[group.SetGroupMemberInfoReq, group.SetGroupMemberInfoResp]("/group/set_group_member_info") - GetIncrementalJoinGroup = newApi[group.GetIncrementalJoinGroupReq, group.GetIncrementalJoinGroupResp]("/group/get_incremental_join_groups") - GetIncrementalGroupMemberBatch = newApi[group.BatchGetIncrementalGroupMemberReq, group.BatchGetIncrementalGroupMemberResp]("/group/get_incremental_group_members_batch") - GetFullJoinedGroupIDs = newApi[group.GetFullJoinGroupIDsReq, group.GetFullJoinGroupIDsResp]("/group/get_full_join_group_ids") - GetFullGroupMemberUserIDs = newApi[group.GetFullGroupMemberUserIDsReq, group.GetFullGroupMemberUserIDsResp]("/group/get_full_group_member_user_ids") + CreateGroup = newApi[group.CreateGroupReq, group.CreateGroupResp]("/group/create_group") + SetGroupInfoEx = newApi[group.SetGroupInfoExReq, group.SetGroupInfoExResp]("/group/set_group_info_ex") + JoinGroup = newApi[group.JoinGroupReq, group.JoinGroupResp]("/group/join_group") + QuitGroup = newApi[group.QuitGroupReq, group.QuitGroupResp]("/group/quit_group") + GetGroupsInfo = newApi[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") + GetGroupMemberList = newApi[group.GetGroupMemberListReq, group.GetGroupMemberListResp]("/group/get_group_member_list") + GetGroupMembersInfo = newApi[group.GetGroupMembersInfoReq, group.GetGroupMembersInfoResp]("/group/get_group_members_info") + InviteUserToGroup = newApi[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") + GetJoinedGroupList = newApi[group.GetJoinedGroupListReq, group.GetJoinedGroupListResp]("/group/get_joined_group_list") + KickGroupMember = newApi[group.KickGroupMemberReq, group.KickGroupMemberResp]("/group/kick_group") + TransferGroup = newApi[group.TransferGroupOwnerReq, group.TransferGroupOwnerResp]("/group/transfer_group") + GetRecvGroupApplicationList = newApi[group.GetGroupApplicationListReq, group.GetGroupApplicationListResp]("/group/get_recv_group_applicationList") + GetSendGroupApplicationList = newApi[group.GetUserReqApplicationListReq, group.GetUserReqApplicationListResp]("/group/get_user_req_group_applicationList") + GetGroupApplicationUnhandledCount = newApi[group.GetGroupApplicationUnhandledCountReq, group.GetGroupApplicationUnhandledCountResp]("/group/get_group_application_unhandled_count") + AcceptGroupApplication = newApi[group.GroupApplicationResponseReq, group.GroupApplicationResponseResp]("/group/group_application_response") + DismissGroup = newApi[group.DismissGroupReq, group.DismissGroupResp]("/group/dismiss_group") + MuteGroupMember = newApi[group.MuteGroupMemberReq, group.MuteGroupMemberResp]("/group/mute_group_member") + CancelMuteGroupMember = newApi[group.CancelMuteGroupMemberReq, group.CancelMuteGroupMemberResp]("/group/cancel_mute_group_member") + MuteGroup = newApi[group.MuteGroupReq, group.MuteGroupResp]("/group/mute_group") + CancelMuteGroup = newApi[group.CancelMuteGroupReq, group.CancelMuteGroupResp]("/group/cancel_mute_group") + SetGroupMemberInfo = newApi[group.SetGroupMemberInfoReq, group.SetGroupMemberInfoResp]("/group/set_group_member_info") + GetIncrementalJoinGroup = newApi[group.GetIncrementalJoinGroupReq, group.GetIncrementalJoinGroupResp]("/group/get_incremental_join_groups") + GetIncrementalGroupMemberBatch = newApi[group.BatchGetIncrementalGroupMemberReq, group.BatchGetIncrementalGroupMemberResp]("/group/get_incremental_group_members_batch") + GetFullJoinedGroupIDs = newApi[group.GetFullJoinGroupIDsReq, group.GetFullJoinGroupIDsResp]("/group/get_full_join_group_ids") + GetFullGroupMemberUserIDs = newApi[group.GetFullGroupMemberUserIDsReq, group.GetFullGroupMemberUserIDsResp]("/group/get_full_group_member_user_ids") ) var ( diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 9a0c02f00..70b8e7868 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -242,13 +242,15 @@ const BigVersion = "v3" const ( MsgSyncBegin = 1001 // - MsgSyncProcessing = 1002 // + MsgSyncData = 1002 // MsgSyncEnd = 1003 // MsgSyncFailed = 1004 AppDataSyncBegin = 1005 - AppDataSyncEnd = 1006 - LargeDataSyncBegin = 1007 - LargeDataSyncEnd = 1008 + AppDataSyncData = 1006 + AppDataSyncEnd = 1007 + LargeDataSyncBegin = 1008 + LargeDataSyncData = 1009 + LargeDataSyncEnd = 1010 ) const ( @@ -259,9 +261,3 @@ const ( const ( Uninitialized = -1001 ) - -// GroupApplicationReceiver -const ( - ApplicantReceiver = iota - AdminReceiver -) diff --git a/pkg/db/db_init.go b/pkg/db/db_init.go index eca95fe21..c515fe5b6 100644 --- a/pkg/db/db_init.go +++ b/pkg/db/db_init.go @@ -173,16 +173,13 @@ func (d *DataBase) versionDataMigrate(ctx context.Context) error { err = d.conn.AutoMigrate( &model_struct.LocalAppSDKVersion{}, &model_struct.LocalFriend{}, - &model_struct.LocalFriendRequest{}, &model_struct.LocalGroup{}, &model_struct.LocalGroupMember{}, - &model_struct.LocalGroupRequest{}, &model_struct.LocalUser{}, &model_struct.LocalBlack{}, &model_struct.LocalConversation{}, &model_struct.NotificationSeqs{}, &model_struct.LocalChatLog{}, - &model_struct.LocalAdminGroupRequest{}, &model_struct.LocalChatLogReactionExtensions{}, &model_struct.LocalUpload{}, &model_struct.LocalStranger{}, diff --git a/pkg/db/db_interface/databse.go b/pkg/db/db_interface/databse.go index a7f939506..33d0e8b02 100644 --- a/pkg/db/db_interface/databse.go +++ b/pkg/db/db_interface/databse.go @@ -30,15 +30,6 @@ type GroupModel interface { GetGroups(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) GetGroupInfoByGroupID(ctx context.Context, groupID string) (*model_struct.LocalGroup, error) GetAllGroupInfoByGroupIDOrGroupName(ctx context.Context, keyword string, isSearchGroupID bool, isSearchGroupName bool) ([]*model_struct.LocalGroup, error) - - InsertAdminGroupRequest(ctx context.Context, groupRequest *model_struct.LocalAdminGroupRequest) error - DeleteAdminGroupRequest(ctx context.Context, groupID, userID string) error - UpdateAdminGroupRequest(ctx context.Context, groupRequest *model_struct.LocalAdminGroupRequest) error - GetAdminGroupApplication(ctx context.Context) ([]*model_struct.LocalAdminGroupRequest, error) - InsertGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error - DeleteGroupRequest(ctx context.Context, groupID, userID string) error - UpdateGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error - GetSendGroupApplication(ctx context.Context) ([]*model_struct.LocalGroupRequest, error) GetGroupMemberInfoByGroupIDUserID(ctx context.Context, groupID, userID string) (*model_struct.LocalGroupMember, error) GetGroupMemberCount(ctx context.Context, groupID string) (int32, error) GetGroupSomeMemberInfo(ctx context.Context, groupID string, userIDList []string) ([]*model_struct.LocalGroupMember, error) @@ -148,13 +139,6 @@ type FriendModel interface { SearchFriendList(ctx context.Context, keyword string, isSearchUserID, isSearchNickname, isSearchRemark bool) ([]*model_struct.LocalFriend, error) GetFriendInfoByFriendUserID(ctx context.Context, FriendUserID string) (*model_struct.LocalFriend, error) GetFriendInfoList(ctx context.Context, friendUserIDList []string) ([]*model_struct.LocalFriend, error) - InsertFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error - DeleteFriendRequestBothUserID(ctx context.Context, fromUserID, toUserID string) error - UpdateFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error - GetRecvFriendApplication(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) - GetSendFriendApplication(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) - GetFriendApplicationByBothID(ctx context.Context, fromUserID, toUserID string) (*model_struct.LocalFriendRequest, error) - GetBothFriendReq(ctx context.Context, fromUserID, toUserID string) ([]*model_struct.LocalFriendRequest, error) UpdateColumnsFriend(ctx context.Context, friendIDs []string, args map[string]interface{}) error GetBlackListDB(ctx context.Context) ([]*model_struct.LocalBlack, error) diff --git a/pkg/db/db_js.go b/pkg/db/db_js.go index cd9f1035d..842e96d27 100644 --- a/pkg/db/db_js.go +++ b/pkg/db/db_js.go @@ -31,10 +31,8 @@ type IndexDB struct { *indexdb.LocalConversationUnreadMessages *indexdb.LocalGroups *indexdb.LocalGroupMember - *indexdb.FriendRequest *indexdb.Black *indexdb.Friend - *indexdb.LocalGroupRequest *indexdb.NotificationSeqs *indexdb.LocalUpload *indexdb.LocalSendingMessages @@ -62,10 +60,8 @@ func NewDataBase(ctx context.Context, loginUserID string, dbDir string, logLevel LocalConversationUnreadMessages: indexdb.NewLocalConversationUnreadMessages(), LocalGroups: indexdb.NewLocalGroups(), LocalGroupMember: indexdb.NewLocalGroupMember(), - FriendRequest: indexdb.NewFriendRequest(loginUserID), Black: indexdb.NewBlack(loginUserID), Friend: indexdb.NewFriend(loginUserID), - LocalGroupRequest: indexdb.NewLocalGroupRequest(), NotificationSeqs: indexdb.NewNotificationSeqs(), LocalUpload: indexdb.NewLocalUpload(), LocalSendingMessages: indexdb.NewLocalSendingMessages(), diff --git a/pkg/db/friend_request_model.go b/pkg/db/friend_request_model.go deleted file mode 100644 index 255412c9c..000000000 --- a/pkg/db/friend_request_model.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright © 2023 OpenIM SDK. 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. - -//go:build !js -// +build !js - -package db - -import ( - "context" - "errors" - - "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/tools/errs" -) - -func (d *DataBase) InsertFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - return errs.WrapMsg(d.conn.WithContext(ctx).Create(friendRequest).Error, "InsertFriendRequest failed") -} - -func (d *DataBase) DeleteFriendRequestBothUserID(ctx context.Context, fromUserID, toUserID string) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - return errs.WrapMsg(d.conn.WithContext(ctx).Where("from_user_id=? and to_user_id=?", fromUserID, toUserID).Delete(&model_struct.LocalFriendRequest{}).Error, "DeleteFriendRequestBothUserID failed") -} - -func (d *DataBase) UpdateFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - t := d.conn.WithContext(ctx).Model(friendRequest).Select("*").Updates(*friendRequest) - if t.RowsAffected == 0 { - return errs.WrapMsg(errors.New("RowsAffected == 0"), "no update") - } - return errs.Wrap(t.Error) -} - -func (d *DataBase) GetRecvFriendApplication(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) { - d.mRWMutex.RLock() - defer d.mRWMutex.RUnlock() - var friendRequestList []*model_struct.LocalFriendRequest - - return friendRequestList, errs.WrapMsg(d.conn.WithContext(ctx).Where("to_user_id = ?", d.loginUserID).Order("create_time DESC").Find(&friendRequestList).Error, "GetRecvFriendApplication failed") -} - -func (d *DataBase) GetSendFriendApplication(ctx context.Context) ([]*model_struct.LocalFriendRequest, error) { - d.mRWMutex.RLock() - defer d.mRWMutex.RUnlock() - var friendRequestList []*model_struct.LocalFriendRequest - return friendRequestList, errs.WrapMsg(d.conn.WithContext(ctx).Where("from_user_id = ?", d.loginUserID).Order("create_time DESC").Find(&friendRequestList).Error, "GetSendFriendApplication failed") -} - -func (d *DataBase) GetFriendApplicationByBothID(ctx context.Context, fromUserID, toUserID string) (*model_struct.LocalFriendRequest, error) { - d.mRWMutex.RLock() - defer d.mRWMutex.RUnlock() - var friendRequest model_struct.LocalFriendRequest - return &friendRequest, errs.WrapMsg(d.conn.WithContext(ctx).Where("from_user_id = ? AND to_user_id = ?", fromUserID, toUserID).Take(&friendRequest).Error, "GetFriendApplicationByBothID failed") -} - -func (d *DataBase) GetBothFriendReq(ctx context.Context, fromUserID, toUserID string) (friendRequests []*model_struct.LocalFriendRequest, err error) { - d.mRWMutex.RLock() - defer d.mRWMutex.RUnlock() - return friendRequests, errs.WrapMsg(d.conn.WithContext(ctx).Where("(from_user_id = ? AND to_user_id = ?) OR (from_user_id = ? AND to_user_id = ?)", fromUserID, toUserID, toUserID, fromUserID).Find(&friendRequests).Error, "GetFriendApplicationByBothID failed") -} diff --git a/pkg/db/group_request_model.go b/pkg/db/group_request_model.go deleted file mode 100644 index 6d2cac141..000000000 --- a/pkg/db/group_request_model.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright © 2023 OpenIM SDK. 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. - -//go:build !js -// +build !js - -package db - -import ( - "context" - "errors" - - "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/tools/errs" -) - -func (d *DataBase) InsertGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - return errs.WrapMsg(d.conn.WithContext(ctx).Create(groupRequest).Error, "InsertGroupRequest failed") -} -func (d *DataBase) DeleteGroupRequest(ctx context.Context, groupID, userID string) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - return errs.WrapMsg(d.conn.WithContext(ctx).Where("group_id=? and user_id=?", groupID, userID).Delete(&model_struct.LocalGroupRequest{}).Error, "DeleteGroupRequest failed") -} -func (d *DataBase) UpdateGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error { - d.mRWMutex.Lock() - defer d.mRWMutex.Unlock() - t := d.conn.WithContext(ctx).Model(groupRequest).Select("*").Updates(*groupRequest) - if t.RowsAffected == 0 { - return errs.WrapMsg(errors.New("RowsAffected == 0"), "no update") - } - return errs.Wrap(t.Error) -} - -func (d *DataBase) GetSendGroupApplication(ctx context.Context) ([]*model_struct.LocalGroupRequest, error) { - d.mRWMutex.RLock() - defer d.mRWMutex.RUnlock() - var groupRequestList []*model_struct.LocalGroupRequest - return groupRequestList, errs.Wrap(d.conn.WithContext(ctx).Order("create_time DESC").Find(&groupRequestList).Error) -} diff --git a/pkg/sdk_params_callback/friend_sdk_struct.go b/pkg/sdk_params_callback/friend_sdk_struct.go index c6e36f3e8..595e23035 100644 --- a/pkg/sdk_params_callback/friend_sdk_struct.go +++ b/pkg/sdk_params_callback/friend_sdk_struct.go @@ -44,3 +44,14 @@ type SetFriendPinParams struct { ToUserIDs []string `json:"toUserIDs" validate:"required"` IsPinned *wrapperspb.BoolValue `json:"isPinned" validate:"required"` } + +type GetFriendApplicationListAsRecipientReq struct { + HandleResults []int32 `json:"handleResults"` + Offset int32 `json:"offset"` + Count int32 `json:"count"` +} + +type GetFriendApplicationListAsApplicantReq struct { + Offset int32 `json:"offset"` + Count int32 `json:"count"` +} diff --git a/pkg/sdk_params_callback/group_sdk_struct.go b/pkg/sdk_params_callback/group_sdk_struct.go index ac4f9292c..ad53866fe 100644 --- a/pkg/sdk_params_callback/group_sdk_struct.go +++ b/pkg/sdk_params_callback/group_sdk_struct.go @@ -29,3 +29,17 @@ type SearchGroupMembersParam struct { Count int `json:"count"` PageNumber int `json:"pageNumber"` } + +type GetGroupApplicationListAsRecipientReq struct { + GroupIDs []string `json:"groupIDs"` + HandleResults []int32 `json:"handleResults"` + Offset int32 `json:"offset"` + Count int32 `json:"count"` +} + +type GetGroupApplicationListAsApplicantReq struct { + GroupIDs []string `json:"groupIDs"` + HandleResults []int32 `json:"handleResults"` + Offset int32 `json:"offset"` + Count int32 `json:"count"` +} diff --git a/wasm/indexdb/friend_request_model.go b/wasm/indexdb/friend_request_model.go deleted file mode 100644 index d358af797..000000000 --- a/wasm/indexdb/friend_request_model.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2023 OpenIM SDK. 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. - -//go:build js && wasm -// +build js,wasm - -package indexdb - -import ( - "context" - "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/openim-sdk-core/v3/pkg/utils" - "github.com/openimsdk/openim-sdk-core/v3/wasm/exec" - "github.com/openimsdk/openim-sdk-core/v3/wasm/indexdb/temp_struct" -) - -type FriendRequest struct { - loginUserID string -} - -func NewFriendRequest(loginUserID string) *FriendRequest { - return &FriendRequest{loginUserID: loginUserID} -} - -func (i FriendRequest) InsertFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error { - _, err := exec.Exec(utils.StructToJsonString(friendRequest)) - return err -} - -func (i FriendRequest) DeleteFriendRequestBothUserID(ctx context.Context, fromUserID, toUserID string) error { - _, err := exec.Exec(fromUserID, toUserID) - return err -} - -func (i FriendRequest) UpdateFriendRequest(ctx context.Context, friendRequest *model_struct.LocalFriendRequest) error { - tempLocalFriendRequest := temp_struct.LocalFriendRequest{ - FromUserID: friendRequest.FromUserID, - FromNickname: friendRequest.FromNickname, - FromFaceURL: friendRequest.FromFaceURL, - ToUserID: friendRequest.ToUserID, - ToNickname: friendRequest.ToNickname, - ToFaceURL: friendRequest.ToFaceURL, - HandleResult: friendRequest.HandleResult, - ReqMsg: friendRequest.ReqMsg, - CreateTime: friendRequest.CreateTime, - HandlerUserID: friendRequest.HandlerUserID, - HandleMsg: friendRequest.HandleMsg, - HandleTime: friendRequest.HandleTime, - Ex: friendRequest.Ex, - AttachedInfo: friendRequest.AttachedInfo, - } - _, err := exec.Exec(utils.StructToJsonString(tempLocalFriendRequest)) - return err -} - -func (i FriendRequest) GetRecvFriendApplication(ctx context.Context) (result []*model_struct.LocalFriendRequest, err error) { - gList, err := exec.Exec(i.loginUserID) - if err != nil { - return nil, err - } else { - if v, ok := gList.(string); ok { - var temp []model_struct.LocalFriendRequest - err := utils.JsonStringToStruct(v, &temp) - if err != nil { - return nil, err - } - for _, v := range temp { - v1 := v - result = append(result, &v1) - } - return result, err - } else { - return nil, exec.ErrType - } - } -} - -func (i FriendRequest) GetSendFriendApplication(ctx context.Context) (result []*model_struct.LocalFriendRequest, err error) { - gList, err := exec.Exec(i.loginUserID) - if err != nil { - return nil, err - } else { - if v, ok := gList.(string); ok { - var temp []model_struct.LocalFriendRequest - err := utils.JsonStringToStruct(v, &temp) - if err != nil { - return nil, err - } - for _, v := range temp { - v1 := v - result = append(result, &v1) - } - return result, err - } else { - return nil, exec.ErrType - } - } -} - -func (i FriendRequest) GetFriendApplicationByBothID(ctx context.Context, fromUserID, toUserID string) (*model_struct.LocalFriendRequest, error) { - c, err := exec.Exec(fromUserID, toUserID) - if err != nil { - return nil, err - } else { - if v, ok := c.(string); ok { - result := model_struct.LocalFriendRequest{} - err := utils.JsonStringToStruct(v, &result) - if err != nil { - return nil, err - } - return &result, err - } else { - return nil, exec.ErrType - } - } -} - -func (i FriendRequest) GetBothFriendReq(ctx context.Context, fromUserID, toUserID string) (result []*model_struct.LocalFriendRequest, err error) { - gList, err := exec.Exec(fromUserID, toUserID) - if err != nil { - return nil, err - } else { - if v, ok := gList.(string); ok { - var temp []model_struct.LocalFriendRequest - err := utils.JsonStringToStruct(v, &temp) - if err != nil { - return nil, err - } - for _, v := range temp { - v1 := v - result = append(result, &v1) - } - return result, err - } else { - return nil, exec.ErrType - } - } -} diff --git a/wasm/indexdb/group_request.model.go b/wasm/indexdb/group_request.model.go deleted file mode 100644 index 285c89ba1..000000000 --- a/wasm/indexdb/group_request.model.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright © 2023 OpenIM SDK. 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. - -//go:build js && wasm -// +build js,wasm - -package indexdb - -import ( - "context" - - "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/openim-sdk-core/v3/pkg/utils" - "github.com/openimsdk/openim-sdk-core/v3/wasm/exec" -) - -type LocalGroupRequest struct { -} - -func NewLocalGroupRequest() *LocalGroupRequest { - return &LocalGroupRequest{} -} - -func (i *LocalGroupRequest) InsertGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error { - _, err := exec.Exec(utils.StructToJsonString(groupRequest)) - return err -} - -func (i *LocalGroupRequest) DeleteGroupRequest(ctx context.Context, groupID, userID string) error { - _, err := exec.Exec(groupID, userID) - return err -} - -func (i *LocalGroupRequest) UpdateGroupRequest(ctx context.Context, groupRequest *model_struct.LocalGroupRequest) error { - _, err := exec.Exec(utils.StructToJsonString(groupRequest)) - return err -} - -func (i *LocalGroupRequest) GetSendGroupApplication(ctx context.Context) ([]*model_struct.LocalGroupRequest, error) { - result, err := exec.Exec() - if err != nil { - return nil, err - } - if v, ok := result.(string); ok { - var request []*model_struct.LocalGroupRequest - if err := utils.JsonStringToStruct(v, &request); err != nil { - return nil, err - } - return request, nil - } else { - return nil, exec.ErrType - } -} - -func (i *LocalGroupRequest) GetAdminGroupApplication(ctx context.Context) ([]*model_struct.LocalAdminGroupRequest, error) { - result, err := exec.Exec() - if err != nil { - return nil, err - } - if v, ok := result.(string); ok { - var request []*model_struct.LocalAdminGroupRequest - if err := utils.JsonStringToStruct(v, &request); err != nil { - return nil, err - } - return request, nil - } else { - return nil, exec.ErrType - } -} - -func (i *LocalGroupRequest) InsertAdminGroupRequest(ctx context.Context, groupRequest *model_struct.LocalAdminGroupRequest) error { - _, err := exec.Exec(utils.StructToJsonString(groupRequest)) - return err -} - -func (i *LocalGroupRequest) DeleteAdminGroupRequest(ctx context.Context, groupID, userID string) error { - _, err := exec.Exec(groupID, userID) - return err -} - -func (i *LocalGroupRequest) UpdateAdminGroupRequest(ctx context.Context, groupRequest *model_struct.LocalAdminGroupRequest) error { - _, err := exec.Exec(utils.StructToJsonString(groupRequest)) - return err -} diff --git a/wasm/indexdb/init.go b/wasm/indexdb/init.go index 784ee7710..b3ea48a49 100644 --- a/wasm/indexdb/init.go +++ b/wasm/indexdb/init.go @@ -46,8 +46,6 @@ type IndexDB struct { LocalConversationUnreadMessages LocalGroups LocalGroupMember - LocalGroupRequest - *FriendRequest *Black *Friend loginUserID string From 866e6022f42e120c95d0e5b7dc2fe3c7a8ded5c8 Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 26 May 2025 11:13:49 +0800 Subject: [PATCH 02/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/group/api.go | 5 ++++- internal/group/server_api.go | 9 +++++++++ internal/relation/api.go | 4 ++++ internal/relation/server_api.go | 8 ++++++++ open_im_sdk/group.go | 4 ++++ open_im_sdk/relation.go | 4 ++++ pkg/sdk_params_callback/group_sdk_struct.go | 8 ++++++++ wasm/cmd/main.go | 2 ++ wasm/wasm_wrapper/wasm_friend.go | 5 +++++ wasm/wasm_wrapper/wasm_group.go | 5 +++++ 10 files changed, 53 insertions(+), 1 deletion(-) diff --git a/internal/group/api.go b/internal/group/api.go index 58c3b4d27..e3bbb8ecc 100644 --- a/internal/group/api.go +++ b/internal/group/api.go @@ -505,7 +505,6 @@ func (g *Group) HandlerGroupApplication(ctx context.Context, req *group.GroupApp if err := g.handlerGroupApplication(ctx, req); err != nil { return err } - // SyncAdminGroupApplication todo return nil } @@ -538,3 +537,7 @@ func (g *Group) CheckGroupMemberFullSync(ctx context.Context, groupID string) (b } return true, nil } + +func (g *Group) GetGroupApplicationUnhandledCount(ctx context.Context, req *sdk_params_callback.GetGroupApplicationUnhandledCountReq) (int32, error) { + return g.getGroupApplicationUnhandledCount(ctx, req.Time) +} diff --git a/internal/group/server_api.go b/internal/group/server_api.go index c9df98108..9b36e0a56 100644 --- a/internal/group/server_api.go +++ b/internal/group/server_api.go @@ -109,3 +109,12 @@ func (g *Group) inviteUserToGroup(ctx context.Context, req *group.InviteUserToGr func (g *Group) handlerGroupApplication(ctx context.Context, req *group.GroupApplicationResponseReq) error { return api.AcceptGroupApplication.Execute(ctx, req) } + +func (g *Group) getGroupApplicationUnhandledCount(ctx context.Context, time int64) (int32, error) { + req := &group.GetGroupApplicationUnhandledCountReq{UserID: g.loginUserID, Time: time} + resp, err := api.GetGroupApplicationUnhandledCount.Invoke(ctx, req) + if err != nil { + return 0, err + } + return int32(resp.GetCount()), nil +} diff --git a/internal/relation/api.go b/internal/relation/api.go index 5d5c5971e..be98ddbe1 100644 --- a/internal/relation/api.go +++ b/internal/relation/api.go @@ -302,3 +302,7 @@ func (r *Relation) UpdateFriends(ctx context.Context, req *relation.UpdateFriend return r.IncrSyncFriends(ctx) } + +func (r *Relation) GetSelfUnhandledApplyCount(ctx context.Context, req *sdk.GetSelfUnhandledApplyCountReq) (int32, error) { + return r.getSelfUnhandledApplyCount(ctx, req.Time) +} diff --git a/internal/relation/server_api.go b/internal/relation/server_api.go index 0d3cbfeb8..83a7f393c 100644 --- a/internal/relation/server_api.go +++ b/internal/relation/server_api.go @@ -72,3 +72,11 @@ func (r *Relation) removeBlack(ctx context.Context, userID string) error { BlackUserID: userID, }) } + +func (r *Relation) getSelfUnhandledApplyCount(ctx context.Context, time int64) (int32, error) { + resp, err := api.GetSelfUnhandledApplyCount.Invoke(ctx, &relation.GetSelfUnhandledApplyCountReq{UserID: r.loginUserID, Time: time}) + if err != nil { + return 0, err + } + return int32(resp.GetCount()), nil +} diff --git a/open_im_sdk/group.go b/open_im_sdk/group.go index 1fc336a66..6256781de 100644 --- a/open_im_sdk/group.go +++ b/open_im_sdk/group.go @@ -127,3 +127,7 @@ func CheckLocalGroupFullSync(callback open_im_sdk_callback.Base, operationID str func CheckGroupMemberFullSync(callback open_im_sdk_callback.Base, operationID string, groupID string, fromUserID string, handleMsg string) { call(callback, operationID, IMUserContext.Group().CheckGroupMemberFullSync, groupID, fromUserID, handleMsg) } + +func GetGroupApplicationUnhandledCount(callback open_im_sdk_callback.Base, operationID string) { + call(callback, operationID, IMUserContext.Group().GetGroupApplicationUnhandledCount) +} diff --git a/open_im_sdk/relation.go b/open_im_sdk/relation.go index 4b2f42387..d1b3a66ed 100644 --- a/open_im_sdk/relation.go +++ b/open_im_sdk/relation.go @@ -75,3 +75,7 @@ func GetBlackList(callback open_im_sdk_callback.Base, operationID string) { func RemoveBlack(callback open_im_sdk_callback.Base, operationID string, removeUserID string) { call(callback, operationID, IMUserContext.Relation().RemoveBlack, removeUserID) } + +func GetSelfUnhandledApplyCount(callback open_im_sdk_callback.Base, operationID string) { + call(callback, operationID, IMUserContext.Relation().GetSelfUnhandledApplyCount) +} diff --git a/pkg/sdk_params_callback/group_sdk_struct.go b/pkg/sdk_params_callback/group_sdk_struct.go index ad53866fe..085d18131 100644 --- a/pkg/sdk_params_callback/group_sdk_struct.go +++ b/pkg/sdk_params_callback/group_sdk_struct.go @@ -43,3 +43,11 @@ type GetGroupApplicationListAsApplicantReq struct { Offset int32 `json:"offset"` Count int32 `json:"count"` } + +type GetGroupApplicationUnhandledCountReq struct { + Time int64 `json:"time"` +} + +type GetSelfUnhandledApplyCountReq struct { + Time int64 `json:"time"` +} diff --git a/wasm/cmd/main.go b/wasm/cmd/main.go index 3df776001..c37d7a066 100644 --- a/wasm/cmd/main.go +++ b/wasm/cmd/main.go @@ -145,6 +145,7 @@ func registerFunc() { js.Global().Set("searchGroupMembers", js.FuncOf(wrapperGroup.SearchGroupMembers)) js.Global().Set("isJoinGroup", js.FuncOf(wrapperGroup.IsJoinGroup)) js.Global().Set("getUsersInGroup", js.FuncOf(wrapperGroup.GetUsersInGroup)) + js.Global().Set("getGroupApplicationUnhandledCount", js.FuncOf(wrapperGroup.GetGroupApplicationUnhandledCount)) wrapperUser := wasm_wrapper.NewWrapperUser(globalFuc) js.Global().Set("getSelfUserInfo", js.FuncOf(wrapperUser.GetSelfUserInfo)) @@ -171,6 +172,7 @@ func registerFunc() { js.Global().Set("getBlackList", js.FuncOf(wrapperFriend.GetBlackList)) js.Global().Set("removeBlack", js.FuncOf(wrapperFriend.RemoveBlack)) js.Global().Set("addBlack", js.FuncOf(wrapperFriend.AddBlack)) + js.Global().Set("getSelfUnhandledApplyCount", js.FuncOf(wrapperFriend.GetSelfUnhandledApplyCount)) wrapperThird := wasm_wrapper.NewWrapperThird(globalFuc) js.Global().Set("updateFcmToken", js.FuncOf(wrapperThird.UpdateFcmToken)) diff --git a/wasm/wasm_wrapper/wasm_friend.go b/wasm/wasm_wrapper/wasm_friend.go index 657328069..ddae346fe 100644 --- a/wasm/wasm_wrapper/wasm_friend.go +++ b/wasm/wasm_wrapper/wasm_friend.go @@ -108,3 +108,8 @@ func (w *WrapperFriend) AddBlack(_ js.Value, args []js.Value) interface{} { callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) return event_listener.NewCaller(open_im_sdk.AddBlack, callback, &args).AsyncCallWithCallback() } + +func (w *WrapperFriend) GetSelfUnhandledApplyCount(_ js.Value, args []js.Value) interface{} { + callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) + return event_listener.NewCaller(open_im_sdk.GetSelfUnhandledApplyCount, callback, &args).AsyncCallWithCallback() +} diff --git a/wasm/wasm_wrapper/wasm_group.go b/wasm/wasm_wrapper/wasm_group.go index 9bd3be962..65fce1ec6 100644 --- a/wasm/wasm_wrapper/wasm_group.go +++ b/wasm/wasm_wrapper/wasm_group.go @@ -173,3 +173,8 @@ func (w *WrapperGroup) GetSpecifiedGroupsInfo(_ js.Value, args []js.Value) inter callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) return event_listener.NewCaller(open_im_sdk.GetSpecifiedGroupsInfo, callback, &args).AsyncCallWithCallback() } + +func (w *WrapperGroup) GetGroupApplicationUnhandledCount(_ js.Value, args []js.Value) interface{} { + callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) + return event_listener.NewCaller(open_im_sdk.GetGroupApplicationUnhandledCount, callback, &args).AsyncCallWithCallback() +} From 16bdcbb7a10b02ec787f8a0436008740d7ef4bbc Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 26 May 2025 16:55:15 +0800 Subject: [PATCH 03/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- open_im_sdk/group.go | 8 ++++---- pkg/sdk_params_callback/friend_sdk_struct.go | 4 ++++ pkg/sdk_params_callback/group_sdk_struct.go | 4 ---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/open_im_sdk/group.go b/open_im_sdk/group.go index 6256781de..56f17d282 100644 --- a/open_im_sdk/group.go +++ b/open_im_sdk/group.go @@ -120,12 +120,12 @@ func RefuseGroupApplication(callback open_im_sdk_callback.Base, operationID stri call(callback, operationID, IMUserContext.Group().RefuseGroupApplication, groupID, fromUserID, handleMsg) } -func CheckLocalGroupFullSync(callback open_im_sdk_callback.Base, operationID string, groupID string, fromUserID string, handleMsg string) { - call(callback, operationID, IMUserContext.Group().CheckLocalGroupFullSync, groupID, fromUserID, handleMsg) +func CheckLocalGroupFullSync(callback open_im_sdk_callback.Base, operationID string) { + call(callback, operationID, IMUserContext.Group().CheckLocalGroupFullSync) } -func CheckGroupMemberFullSync(callback open_im_sdk_callback.Base, operationID string, groupID string, fromUserID string, handleMsg string) { - call(callback, operationID, IMUserContext.Group().CheckGroupMemberFullSync, groupID, fromUserID, handleMsg) +func CheckGroupMemberFullSync(callback open_im_sdk_callback.Base, operationID string, groupID string) { + call(callback, operationID, IMUserContext.Group().CheckGroupMemberFullSync, groupID) } func GetGroupApplicationUnhandledCount(callback open_im_sdk_callback.Base, operationID string) { diff --git a/pkg/sdk_params_callback/friend_sdk_struct.go b/pkg/sdk_params_callback/friend_sdk_struct.go index 595e23035..07b99be36 100644 --- a/pkg/sdk_params_callback/friend_sdk_struct.go +++ b/pkg/sdk_params_callback/friend_sdk_struct.go @@ -55,3 +55,7 @@ type GetFriendApplicationListAsApplicantReq struct { Offset int32 `json:"offset"` Count int32 `json:"count"` } + +type GetSelfUnhandledApplyCountReq struct { + Time int64 `json:"time"` +} diff --git a/pkg/sdk_params_callback/group_sdk_struct.go b/pkg/sdk_params_callback/group_sdk_struct.go index 085d18131..abd3a82f3 100644 --- a/pkg/sdk_params_callback/group_sdk_struct.go +++ b/pkg/sdk_params_callback/group_sdk_struct.go @@ -47,7 +47,3 @@ type GetGroupApplicationListAsApplicantReq struct { type GetGroupApplicationUnhandledCountReq struct { Time int64 `json:"time"` } - -type GetSelfUnhandledApplyCountReq struct { - Time int64 `json:"time"` -} From d5a82d97e08e3159a1a7233365bee5334859db7e Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 26 May 2025 17:06:54 +0800 Subject: [PATCH 04/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- open_im_sdk/group.go | 12 ++++++------ open_im_sdk/relation.go | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/open_im_sdk/group.go b/open_im_sdk/group.go index 56f17d282..144ebb7a2 100644 --- a/open_im_sdk/group.go +++ b/open_im_sdk/group.go @@ -88,12 +88,12 @@ func GetGroupMemberList(callback open_im_sdk_callback.Base, operationID string, call(callback, operationID, IMUserContext.Group().GetGroupMemberList, groupID, filter, offset, count) } -func GetGroupApplicationListAsRecipient(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Group().GetGroupApplicationListAsRecipient) +func GetGroupApplicationListAsRecipient(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Group().GetGroupApplicationListAsRecipient, req) } -func GetGroupApplicationListAsApplicant(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Group().GetGroupApplicationListAsApplicant) +func GetGroupApplicationListAsApplicant(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Group().GetGroupApplicationListAsApplicant, req) } func SearchGroupMembers(callback open_im_sdk_callback.Base, operationID string, searchParam string) { @@ -128,6 +128,6 @@ func CheckGroupMemberFullSync(callback open_im_sdk_callback.Base, operationID st call(callback, operationID, IMUserContext.Group().CheckGroupMemberFullSync, groupID) } -func GetGroupApplicationUnhandledCount(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Group().GetGroupApplicationUnhandledCount) +func GetGroupApplicationUnhandledCount(callback open_im_sdk_callback.Base, operationID string, req string) { + call(callback, operationID, IMUserContext.Group().GetGroupApplicationUnhandledCount, req) } diff --git a/open_im_sdk/relation.go b/open_im_sdk/relation.go index d1b3a66ed..3e74d3117 100644 --- a/open_im_sdk/relation.go +++ b/open_im_sdk/relation.go @@ -48,12 +48,12 @@ func DeleteFriend(callback open_im_sdk_callback.Base, operationID string, friend call(callback, operationID, IMUserContext.Relation().DeleteFriend, friendUserID) } -func GetFriendApplicationListAsRecipient(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Relation().GetFriendApplicationListAsRecipient) +func GetFriendApplicationListAsRecipient(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Relation().GetFriendApplicationListAsRecipient, req) } -func GetFriendApplicationListAsApplicant(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Relation().GetFriendApplicationListAsApplicant) +func GetFriendApplicationListAsApplicant(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Relation().GetFriendApplicationListAsApplicant, req) } func AcceptFriendApplication(callback open_im_sdk_callback.Base, operationID string, userIDHandleMsg string) { @@ -76,6 +76,6 @@ func RemoveBlack(callback open_im_sdk_callback.Base, operationID string, removeU call(callback, operationID, IMUserContext.Relation().RemoveBlack, removeUserID) } -func GetSelfUnhandledApplyCount(callback open_im_sdk_callback.Base, operationID string) { - call(callback, operationID, IMUserContext.Relation().GetSelfUnhandledApplyCount) +func GetSelfUnhandledApplyCount(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Relation().GetSelfUnhandledApplyCount, req) } From c75eb78db4d8e7c0ca952d96f830055a71678b5d Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 26 May 2025 17:43:24 +0800 Subject: [PATCH 05/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/relation/api.go | 2 +- open_im_sdk/relation.go | 4 ++-- wasm/cmd/main.go | 2 +- wasm/wasm_wrapper/wasm_friend.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/relation/api.go b/internal/relation/api.go index be98ddbe1..3cf2b5fb3 100644 --- a/internal/relation/api.go +++ b/internal/relation/api.go @@ -303,6 +303,6 @@ func (r *Relation) UpdateFriends(ctx context.Context, req *relation.UpdateFriend return r.IncrSyncFriends(ctx) } -func (r *Relation) GetSelfUnhandledApplyCount(ctx context.Context, req *sdk.GetSelfUnhandledApplyCountReq) (int32, error) { +func (r *Relation) GetFriendApplicationUnhandledCount(ctx context.Context, req *sdk.GetSelfUnhandledApplyCountReq) (int32, error) { return r.getSelfUnhandledApplyCount(ctx, req.Time) } diff --git a/open_im_sdk/relation.go b/open_im_sdk/relation.go index 3e74d3117..9cc0b8a79 100644 --- a/open_im_sdk/relation.go +++ b/open_im_sdk/relation.go @@ -76,6 +76,6 @@ func RemoveBlack(callback open_im_sdk_callback.Base, operationID string, removeU call(callback, operationID, IMUserContext.Relation().RemoveBlack, removeUserID) } -func GetSelfUnhandledApplyCount(callback open_im_sdk_callback.Base, operationID, req string) { - call(callback, operationID, IMUserContext.Relation().GetSelfUnhandledApplyCount, req) +func GetFriendApplicationUnhandledCount(callback open_im_sdk_callback.Base, operationID, req string) { + call(callback, operationID, IMUserContext.Relation().GetFriendApplicationUnhandledCount, req) } diff --git a/wasm/cmd/main.go b/wasm/cmd/main.go index c37d7a066..33ccbfdbe 100644 --- a/wasm/cmd/main.go +++ b/wasm/cmd/main.go @@ -172,7 +172,7 @@ func registerFunc() { js.Global().Set("getBlackList", js.FuncOf(wrapperFriend.GetBlackList)) js.Global().Set("removeBlack", js.FuncOf(wrapperFriend.RemoveBlack)) js.Global().Set("addBlack", js.FuncOf(wrapperFriend.AddBlack)) - js.Global().Set("getSelfUnhandledApplyCount", js.FuncOf(wrapperFriend.GetSelfUnhandledApplyCount)) + js.Global().Set("getFriendApplicationUnhandledCount", js.FuncOf(wrapperFriend.GetFriendApplicationUnhandledCount)) wrapperThird := wasm_wrapper.NewWrapperThird(globalFuc) js.Global().Set("updateFcmToken", js.FuncOf(wrapperThird.UpdateFcmToken)) diff --git a/wasm/wasm_wrapper/wasm_friend.go b/wasm/wasm_wrapper/wasm_friend.go index ddae346fe..f13e08400 100644 --- a/wasm/wasm_wrapper/wasm_friend.go +++ b/wasm/wasm_wrapper/wasm_friend.go @@ -109,7 +109,7 @@ func (w *WrapperFriend) AddBlack(_ js.Value, args []js.Value) interface{} { return event_listener.NewCaller(open_im_sdk.AddBlack, callback, &args).AsyncCallWithCallback() } -func (w *WrapperFriend) GetSelfUnhandledApplyCount(_ js.Value, args []js.Value) interface{} { +func (w *WrapperFriend) GetFriendApplicationUnhandledCount(_ js.Value, args []js.Value) interface{} { callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) - return event_listener.NewCaller(open_im_sdk.GetSelfUnhandledApplyCount, callback, &args).AsyncCallWithCallback() + return event_listener.NewCaller(open_im_sdk.GetFriendApplicationUnhandledCount, callback, &args).AsyncCallWithCallback() } From 5388a831dcdc59d6d34f2416526532eb98f6309e Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 26 May 2025 18:25:31 +0800 Subject: [PATCH 06/11] fix: refactor friend request and group request handling by removing local caching to relieve synchronization performance pressure. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/group/api.go | 5 +++-- internal/relation/api.go | 5 +++-- pkg/utils/utils.go | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/internal/group/api.go b/internal/group/api.go index e3bbb8ecc..00247c8b4 100644 --- a/internal/group/api.go +++ b/internal/group/api.go @@ -18,6 +18,7 @@ import ( "context" "time" + "github.com/openimsdk/openim-sdk-core/v3/pkg/utils" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/utils/datautil" @@ -415,7 +416,7 @@ func (g *Group) GetGroupMemberList(ctx context.Context, groupID string, filter, } func (g *Group) GetGroupApplicationListAsRecipient(ctx context.Context, req *sdk_params_callback.GetGroupApplicationListAsRecipientReq) ([]*model_struct.LocalGroupRequest, error) { - groupRequests, err := g.getServerAdminGroupApplicationList(ctx, req.GroupIDs, req.HandleResults, req.Offset/req.Count+1, req.Count) + groupRequests, err := g.getServerAdminGroupApplicationList(ctx, req.GroupIDs, req.HandleResults, utils.GetPageNumber(req.Offset, req.Count), req.Count) if err != nil { return nil, err } @@ -423,7 +424,7 @@ func (g *Group) GetGroupApplicationListAsRecipient(ctx context.Context, req *sdk } func (g *Group) GetGroupApplicationListAsApplicant(ctx context.Context, req *sdk_params_callback.GetGroupApplicationListAsApplicantReq) ([]*model_struct.LocalGroupRequest, error) { - groupRequests, err := g.getServerSelfGroupApplication(ctx, req.GroupIDs, req.HandleResults, req.Offset/req.Count+1, req.Count) + groupRequests, err := g.getServerSelfGroupApplication(ctx, req.GroupIDs, req.HandleResults, utils.GetPageNumber(req.Offset, req.Count), req.Count) if err != nil { return nil, err } diff --git a/internal/relation/api.go b/internal/relation/api.go index 3cf2b5fb3..ded611339 100644 --- a/internal/relation/api.go +++ b/internal/relation/api.go @@ -3,6 +3,7 @@ package relation import ( "context" + "github.com/openimsdk/openim-sdk-core/v3/pkg/utils" "github.com/openimsdk/protocol/relation" "github.com/openimsdk/tools/utils/datautil" @@ -73,7 +74,7 @@ func (r *Relation) AddFriend(ctx context.Context, req *relation.ApplyToAddFriend } func (r *Relation) GetFriendApplicationListAsRecipient(ctx context.Context, req *sdk.GetFriendApplicationListAsRecipientReq) ([]*model_struct.LocalFriendRequest, error) { - friendRequests, err := r.getRecvFriendApplicationList(ctx, req.HandleResults, req.Offset/req.Count+1, req.Count) + friendRequests, err := r.getRecvFriendApplicationList(ctx, req.HandleResults, utils.GetPageNumber(req.Offset, req.Count), req.Count) if err != nil { return nil, err } @@ -81,7 +82,7 @@ func (r *Relation) GetFriendApplicationListAsRecipient(ctx context.Context, req } func (r *Relation) GetFriendApplicationListAsApplicant(ctx context.Context, req *sdk.GetFriendApplicationListAsApplicantReq) ([]*model_struct.LocalFriendRequest, error) { - friendRequests, err := r.getSelfFriendApplicationList(ctx, req.Offset/req.Count+1, req.Count) + friendRequests, err := r.getSelfFriendApplicationList(ctx, utils.GetPageNumber(req.Offset, req.Count), req.Count) if err != nil { return nil, err } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 23503e203..3cd1226fe 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -277,3 +277,13 @@ func UnmarshalNotificationElem(bytes []byte, t interface{}) error { } return nil } + +func GetPageNumber(offset, count int32) int32 { + if count <= 0 { + return 1 + } + if offset < 0 { + offset = 0 + } + return offset/count + 1 +} From f6fe300d55426724997d1e8803d4b7cd5667a04f Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Tue, 27 May 2025 19:43:30 +0800 Subject: [PATCH 07/11] fix: group member sync and unread trigger. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/conversation_msg/notification.go | 10 +++++++-- internal/conversation_msg/sync.go | 23 ++++---------------- internal/group/incremental_sync.go | 26 +++++++++++++++++------ pkg/db/conversation_model.go | 14 ++++++++++++ pkg/db/db_interface/databse.go | 1 + wasm/indexdb/conversation_model.go | 14 ++++++++++++ 6 files changed, 61 insertions(+), 27 deletions(-) diff --git a/internal/conversation_msg/notification.go b/internal/conversation_msg/notification.go index d2f67969e..0373e9257 100644 --- a/internal/conversation_msg/notification.go +++ b/internal/conversation_msg/notification.go @@ -88,7 +88,7 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { syncWaitFunctions := []func(c context.Context) error{ c.IncrSyncConversations, - c.SyncAllConUnreadAndCreateNewCon, + c.SyncAllConUnreadAndCreateNewConWithoutTrigger, } runSyncFunctions(ctx, syncWaitFunctions, syncWait) log.ZWarn(ctx, "core data sync over", nil, "cost time", time.Since(c.startTime).Seconds()) @@ -106,6 +106,12 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { c.progress = 100 c.ConversationListener().OnSyncServerProgress(c.progress) c.ConversationListener().OnSyncServerFinish(true) + totalUnreadCount, err := c.db.GetTotalUnreadMsgCountNewerDB(ctx) + if err != nil { + log.ZWarn(ctx, "GetTotalUnreadMsgCountDB err", err) + } else { + c.ConversationListener().OnTotalUnreadMessageCountChanged(totalUnreadCount) + } case constant.MsgSyncData: c.seqs = seqs log.ZDebug(ctx, "MsgSyncBegin") @@ -435,7 +441,7 @@ func (c *Conversation) syncData(c2v common.Cmd2Value) { asyncFuncs := []func(c context.Context) error{ c.user.SyncLoginUserInfo, c.relation.SyncAllBlackList, - c.group.IncrSyncJoinGroupWithLock, + c.group.SyncAllJoinedGroupsAndMembersWithLock, c.relation.IncrSyncFriendsWithLock, c.IncrSyncConversationsWithLock, } diff --git a/internal/conversation_msg/sync.go b/internal/conversation_msg/sync.go index 4bc7e2772..4aa100934 100644 --- a/internal/conversation_msg/sync.go +++ b/internal/conversation_msg/sync.go @@ -21,25 +21,16 @@ import ( "github.com/openimsdk/openim-sdk-core/v3/pkg/common" "github.com/openimsdk/openim-sdk-core/v3/pkg/constant" "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/protocol/msg" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/log" ) -func (c *Conversation) SyncAllConversationHashReadSeqs(ctx context.Context) error { +func (c *Conversation) SyncAllConUnreadAndCreateNewCon(ctx context.Context) error { startTime := time.Now() - log.ZDebug(ctx, "start SyncConversationHashReadSeqs") + log.ZDebug(ctx, "start SyncAllConUnreadAndCreateNewCon") - resp := msg.GetConversationsHasReadAndMaxSeqResp{} - req := msg.GetConversationsHasReadAndMaxSeqReq{UserID: c.loginUserID} - err := c.SendReqWaitResp(ctx, &req, constant.GetConvMaxReadSeq, &resp) - if err != nil { - log.ZWarn(ctx, "SendReqWaitResp err", err) - return err - } - seqs := resp.Seqs - log.ZDebug(ctx, "getServerHasReadAndMaxSeqs completed", "duration", time.Since(startTime).Seconds()) + seqs := c.seqs if len(seqs) == 0 { return nil @@ -135,7 +126,7 @@ func (c *Conversation) SyncAllConversationHashReadSeqs(ctx context.Context) erro return nil } -func (c *Conversation) SyncAllConUnreadAndCreateNewCon(ctx context.Context) error { +func (c *Conversation) SyncAllConUnreadAndCreateNewConWithoutTrigger(ctx context.Context) error { startTime := time.Now() log.ZDebug(ctx, "start SyncAllConUnreadAndCreateNewCon") @@ -224,12 +215,6 @@ func (c *Conversation) SyncAllConUnreadAndCreateNewCon(ctx context.Context) erro } log.ZDebug(ctx, "update conversations", "conversations", conversationChangedIDs) - if len(conversationChangedIDs) > 0 { - stepStartTime = time.Now() - common.DispatchUpdateConversation(ctx, common.UpdateConNode{Action: constant.ConChange, Args: conversationChangedIDs}, c.ConversationEventQueue()) - common.DispatchUpdateConversation(ctx, common.UpdateConNode{Action: constant.TotalUnreadMessageChanged}, c.ConversationEventQueue()) - log.ZDebug(ctx, "DispatchUpdateConversation completed", "duration", time.Since(stepStartTime).Seconds()) - } log.ZDebug(ctx, "SyncAllConversationHashReadSeqs completed", "totalDuration", time.Since(startTime).Seconds()) return nil diff --git a/internal/group/incremental_sync.go b/internal/group/incremental_sync.go index 731d278ab..6b8e9f17e 100644 --- a/internal/group/incremental_sync.go +++ b/internal/group/incremental_sync.go @@ -22,6 +22,26 @@ func (g *Group) groupTableName() string { return model_struct.LocalGroup{}.TableName() } +func (g *Group) SyncAllJoinedGroupsAndMembersWithLock(ctx context.Context) error { + g.groupSyncMutex.Lock() + defer g.groupSyncMutex.Unlock() + if err := g.IncrSyncJoinGroup(ctx); err != nil { + return err + } + return g.IncrSyncJoinGroupMember(ctx) +} + +func (g *Group) IncrSyncJoinGroupMember(ctx context.Context) error { + groups, err := g.db.GetJoinedGroupListDB(ctx) + if err != nil { + return err + } + groupIDs := datautil.Slice(groups, func(e *model_struct.LocalGroup) string { + return e.GroupID + }) + return g.IncrSyncGroupAndMember(ctx, groupIDs...) +} + func (g *Group) IncrSyncGroupAndMember(ctx context.Context, groupIDs ...string) error { var wg sync.WaitGroup if len(groupIDs) == 0 { @@ -333,9 +353,3 @@ func (g *Group) IncrSyncJoinGroup(ctx context.Context) error { } return joinedGroupSyncer.IncrementalSync() } - -func (g *Group) IncrSyncJoinGroupWithLock(ctx context.Context) error { - g.groupSyncMutex.Lock() - defer g.groupSyncMutex.Unlock() - return g.IncrSyncJoinGroup(ctx) -} diff --git a/pkg/db/conversation_model.go b/pkg/db/conversation_model.go index 0008c4e6e..cbb1b1caf 100644 --- a/pkg/db/conversation_model.go +++ b/pkg/db/conversation_model.go @@ -342,6 +342,20 @@ func (d *DataBase) IncrConversationUnreadCount(ctx context.Context, conversation return errs.WrapMsg(t.Error, "IncrConversationUnreadCount failed") } +func (d *DataBase) GetTotalUnreadMsgCountNewerDB(ctx context.Context) (totalUnreadCount int32, err error) { + d.mRWMutex.RLock() + defer d.mRWMutex.RUnlock() + var result []int64 + err = d.conn.WithContext(ctx).Model(&model_struct.LocalConversation{}).Where("recv_msg_opt < ? ", constant.ReceiveNotNotifyMessage).Pluck("unread_count", &result).Error + if err != nil { + return totalUnreadCount, errs.WrapMsg(errors.New("GetTotalUnreadMsgCount err"), "GetTotalUnreadMsgCount err") + } + for _, v := range result { + totalUnreadCount += int32(v) + } + return totalUnreadCount, nil +} + func (d *DataBase) GetTotalUnreadMsgCountDB(ctx context.Context) (totalUnreadCount int32, err error) { d.mRWMutex.RLock() defer d.mRWMutex.RUnlock() diff --git a/pkg/db/db_interface/databse.go b/pkg/db/db_interface/databse.go index 33d0e8b02..61384f201 100644 --- a/pkg/db/db_interface/databse.go +++ b/pkg/db/db_interface/databse.go @@ -112,6 +112,7 @@ type ConversationModel interface { UpdateAllConversation(ctx context.Context, conversation *model_struct.LocalConversation) error IncrConversationUnreadCount(ctx context.Context, conversationID string) error DecrConversationUnreadCount(ctx context.Context, conversationID string, count int64) (err error) + GetTotalUnreadMsgCountNewerDB(ctx context.Context) (totalUnreadCount int32, err error) GetTotalUnreadMsgCountDB(ctx context.Context) (totalUnreadCount int32, err error) SetMultipleConversationRecvMsgOpt(ctx context.Context, conversationIDList []string, opt int) (err error) GetMultipleConversationDB(ctx context.Context, conversationIDList []string) (result []*model_struct.LocalConversation, err error) diff --git a/wasm/indexdb/conversation_model.go b/wasm/indexdb/conversation_model.go index e5a817fd7..3800e5f67 100644 --- a/wasm/indexdb/conversation_model.go +++ b/wasm/indexdb/conversation_model.go @@ -331,6 +331,20 @@ func (i *LocalConversations) GetTotalUnreadMsgCountDB(ctx context.Context) (tota } } } +func (i *LocalConversations) GetTotalUnreadMsgCountNewerDB(ctx context.Context) (totalUnreadCount int32, err error) { + count, err := exec.Exec() + if err != nil { + return 0, err + } else { + if v, ok := count.(float64); ok { + var result int32 + result = int32(v) + return result, err + } else { + return 0, exec.ErrType + } + } +} func (i *LocalConversations) SetMultipleConversationRecvMsgOpt(ctx context.Context, conversationIDList []string, opt int) (err error) { _, err = exec.Exec(utils.StructToJsonString(conversationIDList), opt) From 4783aa6a02f6de741113eb521c7b02de67fa6ff7 Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Fri, 30 May 2025 18:22:07 +0800 Subject: [PATCH 08/11] fix: message sync logic restore. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- go.mod | 4 - go.sum | 2 - internal/conversation_msg/conversation_msg.go | 65 +----- internal/conversation_msg/message_check.go | 53 ----- internal/conversation_msg/notification.go | 35 +-- internal/conversation_msg/skipList.go | 111 --------- internal/conversation_msg/sync.go | 111 ++------- internal/group/group.go | 6 +- internal/interaction/msg_sync.go | 181 ++------------- internal/relation/relation.go | 4 +- internal/user/user.go | 4 +- open_im_sdk/userRelated.go | 6 +- pkg/common/EventQueue.go | 52 ----- pkg/common/EventQueue_test.go | 98 -------- pkg/common/priorityQueue.go | 176 -------------- pkg/common/priorityQueue_test.go | 111 --------- pkg/common/trigger_channel.go | 110 ++++----- pkg/constant/constant.go | 16 +- pkg/sort_conversation/sort_conversation.go | 218 ------------------ 19 files changed, 115 insertions(+), 1248 deletions(-) delete mode 100644 internal/conversation_msg/skipList.go delete mode 100644 pkg/common/EventQueue.go delete mode 100644 pkg/common/EventQueue_test.go delete mode 100644 pkg/common/priorityQueue.go delete mode 100644 pkg/common/priorityQueue_test.go delete mode 100644 pkg/sort_conversation/sort_conversation.go diff --git a/go.mod b/go.mod index 0fb39cc72..f4b3b7047 100644 --- a/go.mod +++ b/go.mod @@ -22,19 +22,16 @@ require ( github.com/openimsdk/protocol v0.0.73-alpha.12 github.com/openimsdk/tools v0.0.50-alpha.80 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/stretchr/testify v1.9.0 golang.org/x/image v0.26.0 golang.org/x/sync v0.13.0 gorm.io/gorm v1.25.10 ) require ( - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect @@ -42,5 +39,4 @@ require ( golang.org/x/text v0.24.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/grpc v1.68.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7ccd86618..f8a2d6dd6 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,6 @@ google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= diff --git a/internal/conversation_msg/conversation_msg.go b/internal/conversation_msg/conversation_msg.go index b7db30be5..86ba79296 100644 --- a/internal/conversation_msg/conversation_msg.go +++ b/internal/conversation_msg/conversation_msg.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "math" - "runtime/debug" "sync" "github.com/openimsdk/openim-sdk-core/v3/pkg/api" @@ -57,7 +56,7 @@ type Conversation struct { msgKvListener func() open_im_sdk_callback.OnMessageKvInfoListener businessListener func() open_im_sdk_callback.OnCustomBusinessListener msgSyncerCh chan common.Cmd2Value - conversationEventQueue *common.EventQueue + conversationEventQueue chan common.Cmd2Value loginUserID string platform int32 DataDir string @@ -80,7 +79,7 @@ type Conversation struct { typing *typing } -func (c *Conversation) ConversationEventQueue() *common.EventQueue { +func (c *Conversation) ConversationEventQueue() chan common.Cmd2Value { return c.conversationEventQueue } @@ -114,7 +113,7 @@ func (c *Conversation) SetBusinessListener(businessListener func() open_im_sdk_c func NewConversation( longConnMgr *interaction.LongConnMgr, - msgSyncerCh chan common.Cmd2Value, conversationEventQueue *common.EventQueue, + msgSyncerCh chan common.Cmd2Value, conversationEventQueue chan common.Cmd2Value, relation *relation.Relation, group *group.Group, user *user.User, file *file.File) *Conversation { @@ -209,6 +208,10 @@ func (c *Conversation) initSyncer() { } +func (c *Conversation) GetCh() chan common.Cmd2Value { + return c.conversationEventQueue +} + type onlineMsgKey struct { ClientMsgID string ServerMsgID string @@ -482,15 +485,13 @@ func (c *Conversation) doMsgSyncByReinstalled(c2v common.Cmd2Value) { c.msgOffset += msgLen total := c2v.Value.(sdk_struct.CmdMsgSyncInReinstall).Total - insertMsg := make(map[string][2][]*model_struct.LocalChatLog, 10) + insertMsg := make(map[string][]*model_struct.LocalChatLog, 10) conversationList := make([]*model_struct.LocalConversation, 0) var exceptionMsg []*model_struct.LocalChatLog log.ZDebug(ctx, "message come here conversation ch in reinstalled", "conversation length", msgLen) b := time.Now() - groupMemberMap := make(map[string][]string, 10) - for conversationID, msgs := range allMsg { log.ZDebug(ctx, "parse message in one conversation", "conversationID", conversationID, "message length", len(msgs.Msgs)) @@ -501,9 +502,6 @@ func (c *Conversation) doMsgSyncByReinstalled(c2v common.Cmd2Value) { continue } for _, v := range msgs.Msgs { - if v.SessionType == constant.ReadGroupChatType { - groupMemberMap[v.GroupID] = append(groupMemberMap[v.GroupID], v.SendID) - } log.ZDebug(ctx, "parse message ", "conversationID", conversationID, "msg", v) msg := &sdk_struct.MsgStruct{} @@ -560,26 +558,11 @@ func (c *Conversation) doMsgSyncByReinstalled(c2v common.Cmd2Value) { log.ZWarn(ctx, "latestMsg is nil", errs.New("latestMsg is nil"), "conversationID", conversationID) } - insertMsg[conversationID] = [2][]*model_struct.LocalChatLog{ - append(insertMessage, selfInsertMessage...), - othersInsertMessage, - } - - } - b1 := time.Now() - // Synchronize the group members for this batch of messages - groupIDs := datautil.Keys(groupMemberMap) - err := c.group.IncrSyncGroupAndMember(ctx, groupIDs...) - if err != nil { - log.ZError(ctx, "IncrSyncGroupAndMember", err) + insertMsg[conversationID] = append(insertMessage, c.faceURLAndNicknameHandle(ctx, selfInsertMessage, othersInsertMessage, conversationID)...) } - log.ZDebug(ctx, "IncrSyncGroupAndMember", "cost time", time.Since(b1).Seconds(), "len", len(allMsg)) - b2 := time.Now() - // Use the latest group member or user information to fill in the profile pictures and nicknames of the messages - mergedInsertMsg := c.FillSenderProfileBatch(ctx, insertMsg) - log.ZDebug(ctx, "FillSenderProfileBatch", "cost time", time.Since(b2).Seconds(), "len", len(allMsg)) + // message storage - _ = c.batchInsertMessageList(ctx, mergedInsertMsg) + _ = c.batchInsertMessageList(ctx, insertMsg) // conversation storage if err := c.db.BatchUpdateConversationList(ctx, conversationList); err != nil { @@ -588,9 +571,7 @@ func (c *Conversation) doMsgSyncByReinstalled(c2v common.Cmd2Value) { log.ZDebug(ctx, "before trigger msg", "cost time", time.Since(b).Seconds(), "len", len(allMsg)) // log.ZDebug(ctx, "progress is", "msgLen", msgLen, "msgOffset", c.msgOffset, "total", total, "now progress is", (c.msgOffset*(100-InitSyncProgress))/total + InitSyncProgress) - if total > 0 { - c.ConversationListener().OnSyncServerProgress((c.msgOffset*(100-InitSyncProgress))/total + InitSyncProgress) - } + c.ConversationListener().OnSyncServerProgress((c.msgOffset*(100-InitSyncProgress))/total + InitSyncProgress) //Exception message storage for _, v := range exceptionMsg { log.ZWarn(ctx, "exceptionMsg show: ", nil, "msg", *v) @@ -945,25 +926,3 @@ func (c *Conversation) getUserNameAndFaceURL(ctx context.Context, userID string) } return userInfo.FaceURL, userInfo.Nickname, nil } - -func (c *Conversation) ConsumeConversationEventLoop(ctx context.Context) { - defer func() { - if r := recover(); r != nil { - err := fmt.Sprintf("panic: %+v\n%s", r, debug.Stack()) - log.ZWarn(ctx, "DoListener panic", nil, "panic info", err) - } - }() - c.conversationEventQueue.ConsumeLoop(ctx, func(ctx context.Context, event *common.Event) { - cmd, ok := event.Data.(common.Cmd2Value) - if !ok { - log.ZWarn(ctx, "invalid event data in conversationEventQueue", nil) - return - } - - log.ZInfo(cmd.Ctx, "recv cmd", "caller", cmd.Caller, "cmd", cmd.Cmd, "value", cmd.Value) - c.Work(cmd) - log.ZInfo(cmd.Ctx, "done cmd", "caller", cmd.Caller, "cmd", cmd.Cmd, "value", cmd.Value) - }, func(msg string, fields ...any) { - log.ZError(ctx, msg, nil, fields...) - }) -} diff --git a/internal/conversation_msg/message_check.go b/internal/conversation_msg/message_check.go index 3989c15df..915b76b03 100644 --- a/internal/conversation_msg/message_check.go +++ b/internal/conversation_msg/message_check.go @@ -634,56 +634,3 @@ func (c *Conversation) groupHandle(ctx context.Context, self, others []*model_st } } - -func (c *Conversation) FillSenderProfileBatch(ctx context.Context, insertMsg map[string][2][]*model_struct.LocalChatLog) map[string][]*model_struct.LocalChatLog { - if len(insertMsg) == 0 { - return map[string][]*model_struct.LocalChatLog{} - } - - conversationIDs := datautil.Keys(insertMsg) - - conversations, err := c.db.GetMultipleConversationDB(ctx, conversationIDs) - if err != nil { - log.ZError(ctx, "GetMultipleConversationDB failed", err) - return mergeInsertMsg(insertMsg) - } - - conversationMap := datautil.SliceToMap(conversations, func(c *model_struct.LocalConversation) string { - return c.ConversationID - }) - - userInfo, err := c.db.GetLoginUser(ctx, c.loginUserID) - if err != nil { - log.ZError(ctx, "GetLoginUser failed", err) - return mergeInsertMsg(insertMsg) - } - - merged := make(map[string][]*model_struct.LocalChatLog, len(insertMsg)) - for conversationID, pair := range insertMsg { - if len(pair[0]) == 0 && len(pair[1]) == 0 { - continue - } - lc, ok := conversationMap[conversationID] - if !ok { - merged[conversationID] = append(pair[0], pair[1]...) - continue - } - switch lc.ConversationType { - case constant.SingleChatType: - c.singleHandle(ctx, pair[0], pair[1], lc, userInfo) - case constant.ReadGroupChatType: - c.groupHandle(ctx, pair[0], pair[1], lc) - } - merged[conversationID] = append(pair[0], pair[1]...) - } - - return merged -} - -func mergeInsertMsg(input map[string][2][]*model_struct.LocalChatLog) map[string][]*model_struct.LocalChatLog { - result := make(map[string][]*model_struct.LocalChatLog, len(input)) - for convID, pair := range input { - result[convID] = append(pair[0], pair[1]...) - } - return result -} diff --git a/internal/conversation_msg/notification.go b/internal/conversation_msg/notification.go index 0373e9257..1df33a537 100644 --- a/internal/conversation_msg/notification.go +++ b/internal/conversation_msg/notification.go @@ -67,18 +67,14 @@ func (c *Conversation) Work(c2v common.Cmd2Value) { func (c *Conversation) syncFlag(c2v common.Cmd2Value) { ctx := c2v.Ctx syncFlag := c2v.Value.(sdk_struct.CmdNewMsgComeToConversation).SyncFlag - seqs := c2v.Value.(sdk_struct.CmdNewMsgComeToConversation).Seqs switch syncFlag { - case constant.AppDataSyncBegin, constant.LargeDataSyncBegin: - c.ConversationListener().OnSyncServerStart(true) - - case constant.AppDataSyncData, constant.LargeDataSyncData: - log.ZDebug(ctx, "AppDataSyncBegin") - c.seqs = seqs + case constant.AppDataSyncStart: + log.ZDebug(ctx, "AppDataSyncStart") c.startTime = time.Now() + c.ConversationListener().OnSyncServerStart(true) c.ConversationListener().OnSyncServerProgress(1) asyncWaitFunctions := []func(c context.Context) error{ - c.group.IncrSyncJoinGroup, + c.group.SyncAllJoinedGroupsAndMembersWithLock, c.relation.IncrSyncFriends, } runSyncFunctions(ctx, asyncWaitFunctions, asyncWait) @@ -86,9 +82,8 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { c.ConversationListener().OnSyncServerProgress(c.progress) // notify server current Progress syncWaitFunctions := []func(c context.Context) error{ - c.IncrSyncConversations, - c.SyncAllConUnreadAndCreateNewConWithoutTrigger, + c.SyncAllConversationHashReadSeqs, } runSyncFunctions(ctx, syncWaitFunctions, syncWait) log.ZWarn(ctx, "core data sync over", nil, "cost time", time.Since(c.startTime).Seconds()) @@ -101,25 +96,15 @@ func (c *Conversation) syncFlag(c2v common.Cmd2Value) { } runSyncFunctions(ctx, asyncNoWaitFunctions, asyncNoWait) - case constant.AppDataSyncEnd, constant.LargeDataSyncEnd: - log.ZDebug(ctx, "AppDataSyncEnd", "time", time.Since(c.startTime).Milliseconds()) + case constant.AppDataSyncFinish: + log.ZDebug(ctx, "AppDataSyncFinish", "time", time.Since(c.startTime).Milliseconds()) c.progress = 100 c.ConversationListener().OnSyncServerProgress(c.progress) c.ConversationListener().OnSyncServerFinish(true) - totalUnreadCount, err := c.db.GetTotalUnreadMsgCountNewerDB(ctx) - if err != nil { - log.ZWarn(ctx, "GetTotalUnreadMsgCountDB err", err) - } else { - c.ConversationListener().OnTotalUnreadMessageCountChanged(totalUnreadCount) - } - case constant.MsgSyncData: - c.seqs = seqs - log.ZDebug(ctx, "MsgSyncBegin") - c.syncData(c2v) - case constant.MsgSyncBegin: + log.ZDebug(ctx, "MsgSyncBegin") c.ConversationListener().OnSyncServerStart(false) - + c.syncData(c2v) case constant.MsgSyncFailed: c.ConversationListener().OnSyncServerFailed(false) case constant.MsgSyncEnd: @@ -432,7 +417,7 @@ func (c *Conversation) syncData(c2v common.Cmd2Value) { // Synchronous sync functions syncFuncs := []func(c context.Context) error{ - c.SyncAllConUnreadAndCreateNewCon, + c.SyncAllConversationHashReadSeqs, } runSyncFunctions(ctx, syncFuncs, syncWait) diff --git a/internal/conversation_msg/skipList.go b/internal/conversation_msg/skipList.go deleted file mode 100644 index 935f99bd3..000000000 --- a/internal/conversation_msg/skipList.go +++ /dev/null @@ -1,111 +0,0 @@ -package conversation_msg - -//type SortConversationList struct { -// list *skiplist.SkipList -// pinnedConversationIDs map[string]struct{} -//} -// -//func NewActiveConversationList(pinnedIDs map[string]struct{}) *SortConversationList { -// return &SortConversationList{ -// list: skiplist.New(skiplist.GreaterThan(func(a, b interface{}) int { -// return compareConversations(a.(*msg.ActiveConversation), b.(*msg.ActiveConversation), pinnedIDs) -// })), -// pinnedConversationIDs: pinnedIDs, -// } -//} -// -// Insert inserts or updates a conversation -//func (acl *SortConversationList) Insert(c *msg.ActiveConversation) { -// acl.Delete(c.ConversationID) -// acl.list.Set(c, c) -//} -// -// Update updates a conversation (same as Insert) -//func (acl *SortConversationList) Update(c *msg.ActiveConversation) { -// acl.Insert(c) -//} -// -// Delete removes a conversation by its ID -//func (acl *SortConversationList) Delete(conversationID string) { -// for e := acl.list.Front(); e != nil; e = e.Next() { -// if e.Value.(*msg.ActiveConversation).ConversationID == conversationID { -// acl.list.Remove(e.Key) -// return -// } -// } -//} -// -// Init initializes the conversation list with the given list of conversations -//func (acl *SortConversationList) Init(conversations []*msg.ActiveConversation) { -// acl.list = skiplist.New(skiplist.GreaterThan(func(a, b interface{}) int { -// return compareConversations(a.(*msg.ActiveConversation), b.(*msg.ActiveConversation), acl.pinnedConversationIDs) -// })) -// for _, c := range conversations { -// acl.Insert(c) -// } -//} -// -// Top returns the top 'limit' conversations -//func (acl *SortConversationList) Top(limit int) []*msg.ActiveConversation { -// res := make([]*msg.ActiveConversation, 0, limit) -// for e := acl.list.Front(); e != nil && (limit <= 0 || len(res) < limit); e = e.Next() { -// res = append(res, e.Value.(*msg.ActiveConversation)) -// } -// return res -//} -// -// After returns the next 'n' conversations after the given conversation ID -//func (acl *SortConversationList) After(conversationID string, n int) []*msg.ActiveConversation { -// var start *skiplist.Element -// for e := acl.list.Front(); e != nil; e = e.Next() { -// if e.Value.(*msg.ActiveConversation).ConversationID == conversationID { -// start = e -// break -// } -// } -// if start == nil { -// return nil -// } -// res := make([]*msg.ActiveConversation, 0, n) -// for e := start.Next(); e != nil && (n <= 0 || len(res) < n); e = e.Next() { -// res = append(res, e.Value.(*msg.ActiveConversation)) -// } -// return res -//} -// -// All returns all conversations -//func (acl *SortConversationList) All() []*msg.ActiveConversation { -// res := make([]*msg.ActiveConversation, 0, acl.list.Len()) -// for e := acl.list.Front(); e != nil; e = e.Next() { -// res = append(res, e.Value.(*msg.ActiveConversation)) -// } -// return res -//} -// -// Comparator for comparing two conversations -//func compareConversations(a, b *msg.ActiveConversation, pinned map[string]struct{}) int { -// _, ap := pinned[a.ConversationID] -// _, bp := pinned[b.ConversationID] -// if ap != bp { -// if ap { -// return 1 -// } -// return -1 -// } -// atime := getEffectiveTime(a) -// btime := getEffectiveTime(b) -// if atime == btime { -// return 0 -// } -// if atime > btime { -// return 1 -// } -// return -1 -//} -// -//func getEffectiveTime(c *msg.ActiveConversation) int64 { -// if c.DraftTime > c.LatestMsgSendTime { -// return c.DraftTime -// } -// return c.LatestMsgSendTime -//} diff --git a/internal/conversation_msg/sync.go b/internal/conversation_msg/sync.go index 4aa100934..6da09a55c 100644 --- a/internal/conversation_msg/sync.go +++ b/internal/conversation_msg/sync.go @@ -21,16 +21,25 @@ import ( "github.com/openimsdk/openim-sdk-core/v3/pkg/common" "github.com/openimsdk/openim-sdk-core/v3/pkg/constant" "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" + "github.com/openimsdk/protocol/msg" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/log" ) -func (c *Conversation) SyncAllConUnreadAndCreateNewCon(ctx context.Context) error { +func (c *Conversation) SyncAllConversationHashReadSeqs(ctx context.Context) error { startTime := time.Now() - log.ZDebug(ctx, "start SyncAllConUnreadAndCreateNewCon") + log.ZDebug(ctx, "start SyncConversationHashReadSeqs") - seqs := c.seqs + resp := msg.GetConversationsHasReadAndMaxSeqResp{} + req := msg.GetConversationsHasReadAndMaxSeqReq{UserID: c.loginUserID} + err := c.SendReqWaitResp(ctx, &req, constant.GetConvMaxReadSeq, &resp) + if err != nil { + log.ZWarn(ctx, "SendReqWaitResp err", err) + return err + } + seqs := resp.Seqs + log.ZDebug(ctx, "getServerHasReadAndMaxSeqs completed", "duration", time.Since(startTime).Seconds()) if len(seqs) == 0 { return nil @@ -119,102 +128,8 @@ func (c *Conversation) SyncAllConUnreadAndCreateNewCon(ctx context.Context) erro stepStartTime = time.Now() common.DispatchUpdateConversation(ctx, common.UpdateConNode{Action: constant.ConChange, Args: conversationChangedIDs}, c.ConversationEventQueue()) common.DispatchUpdateConversation(ctx, common.UpdateConNode{Action: constant.TotalUnreadMessageChanged}, c.ConversationEventQueue()) - log.ZDebug(ctx, "DispatchUpdateConversation completed", "duration", time.Since(stepStartTime).Seconds()) - } - - log.ZDebug(ctx, "SyncAllConversationHashReadSeqs completed", "totalDuration", time.Since(startTime).Seconds()) - return nil -} - -func (c *Conversation) SyncAllConUnreadAndCreateNewConWithoutTrigger(ctx context.Context) error { - startTime := time.Now() - log.ZDebug(ctx, "start SyncAllConUnreadAndCreateNewCon") - - seqs := c.seqs - - if len(seqs) == 0 { - return nil - } - var conversationChangedIDs []string - var conversationIDsNeedSync []string - - stepStartTime := time.Now() - conversationsOnLocal, err := c.db.GetAllConversations(ctx) - if err != nil { - log.ZWarn(ctx, "get all conversations err", err) - return err - } - log.ZDebug(ctx, "GetAllConversations completed", "duration", time.Since(stepStartTime).Seconds()) - - conversationsOnLocalMap := datautil.SliceToMap(conversationsOnLocal, func(e *model_struct.LocalConversation) string { - return e.ConversationID - }) - - stepStartTime = time.Now() - for conversationID, v := range seqs { - var unreadCount int32 - c.maxSeqRecorder.Set(conversationID, v.MaxSeq) - if v.MaxSeq-v.HasReadSeq < 0 { - unreadCount = 0 - log.ZWarn(ctx, "unread count is less than 0", nil, "conversationID", - conversationID, "maxSeq", v.MaxSeq, "hasReadSeq", v.HasReadSeq) - } else { - unreadCount = int32(v.MaxSeq - v.HasReadSeq) - } - if conversation, ok := conversationsOnLocalMap[conversationID]; ok { - if conversation.UnreadCount != unreadCount { - if err := c.db.UpdateColumnsConversation(ctx, conversationID, map[string]interface{}{"unread_count": unreadCount}); err != nil { - log.ZWarn(ctx, "UpdateColumnsConversation err", err, "conversationID", conversationID) - continue - } - conversationChangedIDs = append(conversationChangedIDs, conversationID) - } - } else { - conversationIDsNeedSync = append(conversationIDsNeedSync, conversationID) - } + log.ZDebug(ctx, "TriggerCmdUpdateConversation completed", "duration", time.Since(stepStartTime).Seconds()) } - log.ZDebug(ctx, "Process seqs completed", "duration", time.Since(stepStartTime).Seconds()) - - if len(conversationIDsNeedSync) > 0 { - stepStartTime = time.Now() - r, err := c.getConversationsByIDsFromServer(ctx, conversationIDsNeedSync) - if err != nil { - log.ZWarn(ctx, "getServerConversationsByIDs err", err, "conversationIDs", conversationIDsNeedSync) - return err - } - log.ZDebug(ctx, "getServerConversationsByIDs completed", "duration", time.Since(stepStartTime).Seconds()) - conversationsOnServer := datautil.Batch(ServerConversationToLocal, r.Conversations) - stepStartTime = time.Now() - if err := c.batchAddFaceURLAndName(ctx, conversationsOnServer...); err != nil { - log.ZWarn(ctx, "batchAddFaceURLAndName err", err, "conversationsOnServer", conversationsOnServer) - return err - } - log.ZDebug(ctx, "batchAddFaceURLAndName completed", "duration", time.Since(stepStartTime).Seconds()) - - for _, conversation := range conversationsOnServer { - var unreadCount int32 - v, ok := seqs[conversation.ConversationID] - if !ok { - continue - } - if v.MaxSeq-v.HasReadSeq < 0 { - unreadCount = 0 - log.ZWarn(ctx, "unread count is less than 0", nil, "server seq", v, "conversation", conversation) - } else { - unreadCount = int32(v.MaxSeq - v.HasReadSeq) - } - conversation.UnreadCount = unreadCount - } - - stepStartTime = time.Now() - err = c.db.BatchInsertConversationList(ctx, conversationsOnServer) - if err != nil { - log.ZWarn(ctx, "BatchInsertConversationList err", err, "conversationsOnServer", conversationsOnServer) - } - log.ZDebug(ctx, "BatchInsertConversationList completed", "duration", time.Since(stepStartTime).Seconds()) - } - - log.ZDebug(ctx, "update conversations", "conversations", conversationChangedIDs) log.ZDebug(ctx, "SyncAllConversationHashReadSeqs completed", "totalDuration", time.Since(startTime).Seconds()) return nil diff --git a/internal/group/group.go b/internal/group/group.go index d08289dc0..17cb21373 100644 --- a/internal/group/group.go +++ b/internal/group/group.go @@ -38,14 +38,14 @@ import ( ) const ( - groupSyncLimit = 1047 + groupSyncLimit = 1000 groupMemberSyncLimit = 1000 NotificationFilterCacheSize = 1024 NotificationFilterTimeout = 10 * time.Second ) func NewGroup( - conversationEventQueue *common.EventQueue) *Group { + conversationEventQueue chan common.Cmd2Value) *Group { g := &Group{ conversationEventQueue: conversationEventQueue, filter: NewNotificationFilter(NotificationFilterCacheSize, NotificationFilterTimeout), @@ -61,7 +61,7 @@ type Group struct { db db_interface.DataBase groupSyncer *syncer.Syncer[*model_struct.LocalGroup, group.GetJoinedGroupListResp, string] groupMemberSyncer *syncer.Syncer[*model_struct.LocalGroupMember, group.GetGroupMemberListResp, [2]string] - conversationEventQueue *common.EventQueue + conversationEventQueue chan common.Cmd2Value groupSyncMutex sync.Mutex listenerForService open_im_sdk_callback.OnListenerForService groupMemberCache *cache.Cache[string, *model_struct.LocalGroupMember] diff --git a/internal/interaction/msg_sync.go b/internal/interaction/msg_sync.go index f31acbd78..d9d53f821 100644 --- a/internal/interaction/msg_sync.go +++ b/internal/interaction/msg_sync.go @@ -29,15 +29,10 @@ import ( "github.com/openimsdk/openim-sdk-core/v3/pkg/constant" "github.com/openimsdk/openim-sdk-core/v3/pkg/db/db_interface" "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" - "github.com/openimsdk/openim-sdk-core/v3/pkg/sort_conversation" "github.com/openimsdk/openim-sdk-core/v3/sdk_struct" "github.com/openimsdk/protocol/msg" - "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/mcontext" - "github.com/openimsdk/tools/utils/datautil" - "github.com/openimsdk/tools/utils/stringutil" - "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" ) @@ -53,19 +48,16 @@ const ( // MsgSyncer is a central hub for message relay, responsible for sequential message gap pulling, // handling network events, and managing app foreground and background events. type MsgSyncer struct { - loginUserID string // login user ID - longConnMgr *LongConnMgr // long connection manager - recvCh chan common.Cmd2Value // channel for receiving push messages and the maximum SEQ number - //conversationEventQueue chan common.Cmd2Value // storage and session triggering - conversationEventQueue *common.EventQueue + loginUserID string // login user ID + longConnMgr *LongConnMgr // long connection manager + PushMsgAndMaxSeqCh chan common.Cmd2Value // channel for receiving push messages and the maximum SEQ number + conversationEventQueue chan common.Cmd2Value // storage and session triggering syncedMaxSeqs map[string]int64 // map of the maximum synced SEQ numbers for all group IDs syncedMaxSeqsLock sync.RWMutex // syncedMaxSeqs map lock db db_interface.DataBase // data store reinstalled bool //true if the app was uninstalled and reinstalled isSyncing bool // indicates whether data is being synced isSyncingLock sync.Mutex // lock for syncing state - - isLargeDataSync bool } func (m *MsgSyncer) SetLoginUserID(loginUserID string) { @@ -77,11 +69,11 @@ func (m *MsgSyncer) SetDataBase(db db_interface.DataBase) { } // NewMsgSyncer creates a new instance of the message synchronizer. -func NewMsgSyncer(recvCh chan common.Cmd2Value, conversationEventQueue *common.EventQueue, +func NewMsgSyncer(conversationEventQueue, PushMsgAndMaxSeqCh chan common.Cmd2Value, longConnMgr *LongConnMgr) *MsgSyncer { return &MsgSyncer{ longConnMgr: longConnMgr, - recvCh: recvCh, + PushMsgAndMaxSeqCh: PushMsgAndMaxSeqCh, conversationEventQueue: conversationEventQueue, syncedMaxSeqs: make(map[string]int64), } @@ -180,7 +172,7 @@ func (m *MsgSyncer) DoListener(ctx context.Context) { }() for { select { - case cmd := <-m.recvCh: + case cmd := <-m.PushMsgAndMaxSeqCh: m.handlePushMsgAndEvent(cmd) case <-ctx.Done(): log.ZInfo(ctx, "msg syncer done, sdk logout.....") @@ -337,7 +329,7 @@ func (m *MsgSyncer) compareSeqsAndBatchSync(ctx context.Context, maxSeqToSync ma } m.reinstalled = false }() - _ = m.syncAndTriggerReinstallMsgs(ctx, needSyncSeqMap, true, pullNums) + _ = m.syncAndTriggerReinstallMsgs(ctx, needSyncSeqMap, pullNums) } else { for conversationID, maxSeq := range maxSeqToSync { if syncedMaxSeq, ok := m.syncedMaxSeqs[conversationID]; ok { @@ -417,9 +409,9 @@ func (m *MsgSyncer) pushTriggerAndSync(ctx context.Context, pushMessages map[str func (m *MsgSyncer) doConnected(ctx context.Context) { reinstalled := m.reinstalled if reinstalled { - common.DispatchSyncFlagWithMeta(ctx, constant.AppDataSyncBegin, nil, m.conversationEventQueue) + common.DispatchSyncFlag(ctx, constant.AppDataSyncStart, m.conversationEventQueue) } else { - common.DispatchSyncFlagWithMeta(ctx, constant.MsgSyncBegin, nil, m.conversationEventQueue) + common.DispatchSyncFlag(ctx, constant.MsgSyncBegin, m.conversationEventQueue) } var resp sdkws.GetMaxSeqResp if err := m.longConnMgr.SendReqWaitResp(ctx, &sdkws.GetMaxSeqReq{UserID: m.loginUserID}, constant.GetNewestSeq, &resp); err != nil { @@ -429,78 +421,11 @@ func (m *MsgSyncer) doConnected(ctx context.Context) { } else { log.ZDebug(ctx, "get max seq success", "resp", resp.MaxSeqs) } - - // Calculate the list of conversations that need to be synchronized, - // including the start and end sequence (seq) - needSyncAllSeqMap := m.getNeedSyncConversations(ctx, resp.MaxSeqs) - convCount := len(needSyncAllSeqMap) - - if convCount == 0 { - log.ZInfo(ctx, "no conversations messages need to sync") - } - - // In cases where there is no uninstall and reinstall, - // the amount of conversation data to be synchronized in a single operation is too large - if len(needSyncAllSeqMap) >= maxConversations { - log.ZDebug(ctx, "large conversations to sync", "length", len(needSyncAllSeqMap)) - m.isLargeDataSync = true - common.DispatchSyncFlagWithMeta(ctx, constant.LargeDataSyncBegin, nil, m.conversationEventQueue) - } - - maxSeqs, sortConversationList, err := m.SyncAndSortConversations(ctx, reinstalled) - if err != nil { - log.ZError(ctx, "SyncAndSortConversations err", err) - } - if reinstalled { - common.DispatchSyncFlagWithMeta(ctx, constant.AppDataSyncData, maxSeqs, m.conversationEventQueue) - } else { - if m.isLargeDataSync { - log.ZWarn(ctx, "too many conversations to sync", nil, "maxConversations", maxConversations) - common.DispatchSyncFlagWithMeta(ctx, constant.LargeDataSyncData, maxSeqs, m.conversationEventQueue) - } else { - common.DispatchSyncFlagWithMeta(ctx, constant.MsgSyncData, maxSeqs, m.conversationEventQueue) - } - } - - sort_conversation.NewConversationBatchProcessor(sortConversationList, needSyncAllSeqMap, synMaxConversations).Run(ctx, m.handleMessage) - - if reinstalled { - defer m.markInstallDone(ctx) - - } else { - if !m.isLargeDataSync { - common.DispatchSyncFlag(ctx, constant.MsgSyncEnd, m.conversationEventQueue) - } - - } -} - -func (m *MsgSyncer) markInstallDone(ctx context.Context) { - if err := m.db.SetAppSDKVersion(ctx, &model_struct.LocalAppSDKVersion{Installed: true}); err != nil { - log.ZError(ctx, "SetAppSDKVersion failed", err) - } - m.reinstalled = false -} -func (m *MsgSyncer) handleMessage(ctx context.Context, batchID int, needSyncTopSeqMap map[string][2]int64, isFirst bool) { - ctx = mcontext.WithTriggerIDContext(ctx, stringutil.IntToString(batchID)) - reinstalled := m.reinstalled - log.ZDebug(ctx, "handle message need sync top message map", "length", len(needSyncTopSeqMap), "needSyncTopSeqMap", needSyncTopSeqMap) - + m.compareSeqsAndBatchSync(ctx, resp.MaxSeqs, connectPullNums) if reinstalled { - _ = m.syncAndTriggerReinstallMsgs(ctx, needSyncTopSeqMap, isFirst, connectPullNums) - if isFirst { - common.DispatchSyncFlag(ctx, constant.AppDataSyncEnd, m.conversationEventQueue) - } + common.DispatchSyncFlag(ctx, constant.AppDataSyncFinish, m.conversationEventQueue) } else { - if m.isLargeDataSync { - log.ZDebug(ctx, "handleMessage large conversations to sync", "length", len(needSyncTopSeqMap), "isFirst", isFirst, "maxConversations", maxConversations) - _ = m.syncAndTriggerReinstallMsgs(ctx, needSyncTopSeqMap, isFirst, connectPullNums) - if isFirst { - common.DispatchSyncFlag(ctx, constant.LargeDataSyncEnd, m.conversationEventQueue) - } - } else { - _ = m.syncAndTriggerMsgs(ctx, needSyncTopSeqMap, connectPullNums) - } + common.DispatchSyncFlag(ctx, constant.MsgSyncEnd, m.conversationEventQueue) } } @@ -597,26 +522,22 @@ func (m *MsgSyncer) syncAndTriggerMsgs(ctx context.Context, seqMap map[string][2 } // Fragment synchronization message, seq refresh after successful trigger -func (m *MsgSyncer) syncAndTriggerReinstallMsgs(ctx context.Context, seqMap map[string][2]int64, isFirst bool, syncMsgNum int64) error { +func (m *MsgSyncer) syncAndTriggerReinstallMsgs(ctx context.Context, seqMap map[string][2]int64, syncMsgNum int64) error { if len(seqMap) > 0 { log.ZDebug(ctx, "current sync seqMap", "seqMap", seqMap) var ( tempSeqMap = make(map[string][2]int64, 50) msgNum = 0 - total = 0 + total = len(seqMap) gr *errgroup.Group ) - if isFirst { - total = len(seqMap) - } + gr, _ = errgroup.WithContext(ctx) gr.SetLimit(pullMsgGoroutineLimit) for k, v := range seqMap { oneConversationSyncNum := min(v[1]-v[0]+1, syncMsgNum) tempSeqMap[k] = v - if IsNotification(k) { - msgNum += int(oneConversationSyncNum) - } else { + if oneConversationSyncNum > 0 { // For regular conversations, ensure msgNum is the minimum of oneConversationSyncNum and syncMsgNum msgNum += int(min(oneConversationSyncNum, syncMsgNum)) } @@ -811,69 +732,3 @@ func (m *MsgSyncer) triggerNotification(ctx context.Context, msgs map[string]*sd return nil } - -func (m *MsgSyncer) SyncAndSortConversations(ctx context.Context, reinstalled bool) (map[string]*msg.Seqs, *sort_conversation.SortConversationList, error) { - startTime := time.Now() - log.ZDebug(ctx, "start SyncConversationHashReadSeqs") - - resp := msg.GetConversationsHasReadAndMaxSeqResp{} - req := msg.GetConversationsHasReadAndMaxSeqReq{UserID: m.loginUserID, ReturnPinned: reinstalled} - err := m.longConnMgr.SendReqWaitResp(ctx, &req, constant.GetConvMaxReadSeq, &resp) - if err != nil { - log.ZWarn(ctx, "SendReqWaitResp err", err) - return nil, nil, err - } - seqs := resp.Seqs - log.ZDebug(ctx, "getServerHasReadAndMaxSeqs completed", "duration", time.Since(startTime).Seconds()) - - if len(seqs) == 0 { - return nil, nil, nil - } - - stepStartTime := time.Now() - conversationsOnLocal, err := m.db.GetAllConversations(ctx) - if err != nil { - log.ZWarn(ctx, "get all conversations err", err) - return nil, nil, err - } - log.ZDebug(ctx, "GetAllConversations completed", "duration", time.Since(stepStartTime).Seconds()) - - conversationsOnLocalMap := datautil.SliceToMap(conversationsOnLocal, func(e *model_struct.LocalConversation) string { - return e.ConversationID - }) - - var ( - list []*sort_conversation.ConversationMetaData - pinnedConversationIDs []string - ) - pinnedConversationIDsMap := datautil.SliceSetAny(resp.PinnedConversationIDs, func(e string) string { - return e - }) - stepStartTime = time.Now() - for conversationID, v := range seqs { - sortConversationMetaData := &sort_conversation.ConversationMetaData{ - ConversationID: conversationID, - LatestMsgSendTime: v.MaxSeqTime, - } - if _, ok := pinnedConversationIDsMap[conversationID]; ok { - sortConversationMetaData.IsPinned = true - pinnedConversationIDs = append(pinnedConversationIDs, conversationID) - } - - if conversation, ok := conversationsOnLocalMap[conversationID]; ok { - if conversation.IsPinned { - sortConversationMetaData.IsPinned = true - pinnedConversationIDs = append(pinnedConversationIDs, conversationID) - } - if conversation.DraftTextTime > 0 { - sortConversationMetaData.DraftTextTime = conversation.DraftTextTime - } - } - list = append(list, sortConversationMetaData) - } - - sortConversationList := sort_conversation.NewSortConversationList(list, pinnedConversationIDs) - - log.ZDebug(ctx, "Process seqs completed", "duration", time.Since(stepStartTime).Seconds()) - return resp.Seqs, sortConversationList, nil -} diff --git a/internal/relation/relation.go b/internal/relation/relation.go index dcd9dda33..6bba1592b 100644 --- a/internal/relation/relation.go +++ b/internal/relation/relation.go @@ -24,7 +24,7 @@ const ( friendSyncLimit int64 = 10000 ) -func NewRelation(conversationEventQueue *common.EventQueue, user *user.User) *Relation { +func NewRelation(conversationEventQueue chan common.Cmd2Value, user *user.User) *Relation { r := &Relation{conversationEventQueue: conversationEventQueue, user: user} r.initSyncer() return r @@ -37,7 +37,7 @@ type Relation struct { user *user.User friendSyncer *syncer.Syncer[*model_struct.LocalFriend, relation.GetPaginationFriendsResp, [2]string] blackSyncer *syncer.Syncer[*model_struct.LocalBlack, syncer.NoResp, [2]string] - conversationEventQueue *common.EventQueue + conversationEventQueue chan common.Cmd2Value listenerForService open_im_sdk_callback.OnListenerForService relationSyncMutex sync.Mutex } diff --git a/internal/user/user.go b/internal/user/user.go index 71fdf18c4..ce5734d9d 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -34,7 +34,7 @@ import ( ) // NewUser creates a new User object. -func NewUser(conversationEventQueue *common.EventQueue) *User { +func NewUser(conversationEventQueue chan common.Cmd2Value) *User { user := &User{conversationEventQueue: conversationEventQueue} user.initSyncer() return user @@ -46,7 +46,7 @@ type User struct { loginUserID string listener func() open_im_sdk_callback.OnUserListener userSyncer *syncer.Syncer[*model_struct.LocalUser, syncer.NoResp, string] - conversationEventQueue *common.EventQueue + conversationEventQueue chan common.Cmd2Value userCache *cache.UserCache[string, *model_struct.LocalUser] once sync.Once diff --git a/open_im_sdk/userRelated.go b/open_im_sdk/userRelated.go index 0487bc4f2..a5a5e9237 100644 --- a/open_im_sdk/userRelated.go +++ b/open_im_sdk/userRelated.go @@ -79,7 +79,7 @@ func (u *UserContext) initResources() { ctx := ccontext.WithInfo(context.Background(), u.info) u.ctx, u.cancel = context.WithCancel(ctx) u.setFGCtx() - u.conversationEventQueue = common.NewEventQueue(1000) + u.conversationEventQueue = make(chan common.Cmd2Value, 1000) u.msgSyncerCh = make(chan common.Cmd2Value, 1000) u.loginMgrCh = make(chan common.Cmd2Value, 1) @@ -146,7 +146,7 @@ type UserContext struct { //conversationCh chan common.Cmd2Value - conversationEventQueue *common.EventQueue + conversationEventQueue chan common.Cmd2Value cmdWsCh chan common.Cmd2Value msgSyncerCh chan common.Cmd2Value loginMgrCh chan common.Cmd2Value @@ -434,7 +434,7 @@ func setListener[T any](ctx context.Context, listener *T, getter func() T, setFu func (u *UserContext) run(ctx context.Context) { u.longConnMgr.Run(ctx, u.fgCtx) go u.msgSyncer.DoListener(ctx) - go u.conversation.ConsumeConversationEventLoop(ctx) + go common.DoListener(u.ctx, u.conversation) go u.logoutListener(ctx) } diff --git a/pkg/common/EventQueue.go b/pkg/common/EventQueue.go deleted file mode 100644 index 0baf19741..000000000 --- a/pkg/common/EventQueue.go +++ /dev/null @@ -1,52 +0,0 @@ -package common - -import ( - "context" -) - -type EventHandler func(ctx context.Context, event *Event) - -type LogCallback func(msg string, fields ...any) - -// EventQueue is responsible for concurrently consuming events from the PriorityQueue -type EventQueue struct { - queue *PriorityQueue -} - -// NewEventQueue creates a worker pool instance -func NewEventQueue(capacity int) *EventQueue { - return &EventQueue{ - queue: NewPriorityQueue(capacity), - } -} - -func (e *EventQueue) Produce(data any, priority int) (*Event, error) { - event := &Event{Data: data, Priority: priority} - err := e.queue.Push(event) - return event, err -} -func (q *EventQueue) ProduceWithContext(ctx context.Context, data any, priority int) (*Event, error) { - event := &Event{Data: data, Priority: priority} - return event, q.queue.PushWithContext(ctx, event) -} - -func (e *EventQueue) UpdatePriority(event *Event, newPriority int) error { - return e.queue.UpdatePriority(event, newPriority) -} - -func (e *EventQueue) ConsumeLoop(ctx context.Context, handle EventHandler, log LogCallback) { - for { - event, err := e.queue.PopWithContext(ctx) - if err != nil { - select { - case <-ctx.Done(): - log("ctx canceled", err) - return - default: - log("pop error", err) - continue - } - } - handle(ctx, event) - } -} diff --git a/pkg/common/EventQueue_test.go b/pkg/common/EventQueue_test.go deleted file mode 100644 index ee90d6969..000000000 --- a/pkg/common/EventQueue_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package common - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestEventQueue_ProduceAndConsume(t *testing.T) { - var ( - mu sync.Mutex - handledOrder []string - ) - - handler := func(ctx context.Context, event *Event) { - mu.Lock() - handledOrder = append(handledOrder, event.Data.(string)) - mu.Unlock() - } - - logCallback := func(msg string, fields ...any) { - - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - eq := NewEventQueue(10) - - _, _ = eq.Produce("low1", 1) - _, _ = eq.Produce("medium", 5) - _, _ = eq.Produce("low2", 1) - _, _ = eq.Produce("high", 10) - - go eq.ConsumeLoop(ctx, handler, logCallback) - - time.Sleep(500 * time.Millisecond) - cancel() - - mu.Lock() - defer mu.Unlock() - assert.Equal(t, []string{"high", "medium", "low1", "low2"}, handledOrder) -} - -func TestEventQueue_CancelContext(t *testing.T) { - called := false - - handler := func(ctx context.Context, event *Event) { - called = true - } - - logCallback := func(msg string, fields ...any) {} - - ctx, cancel := context.WithCancel(context.Background()) - eq := NewEventQueue(1) - - go eq.ConsumeLoop(ctx, handler, logCallback) - - cancel() - time.Sleep(100 * time.Millisecond) - - assert.False(t, called) -} - -func TestEventQueue_UpdatePriority(t *testing.T) { - var mu sync.Mutex - var results []string - - handler := func(ctx context.Context, event *Event) { - mu.Lock() - results = append(results, event.Data.(string)) - mu.Unlock() - } - - logCallback := func(msg string, fields ...any) {} - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - eq := NewEventQueue(5) - go eq.ConsumeLoop(ctx, handler, logCallback) - - e1, _ := eq.Produce("a", 1) - _, _ = eq.Produce("b", 2) - - time.Sleep(50 * time.Millisecond) - _ = eq.UpdatePriority(e1, 5) - - time.Sleep(500 * time.Millisecond) - cancel() - - mu.Lock() - defer mu.Unlock() - assert.Equal(t, []string{"a", "b"}, results) -} diff --git a/pkg/common/priorityQueue.go b/pkg/common/priorityQueue.go deleted file mode 100644 index 2ed6151f1..000000000 --- a/pkg/common/priorityQueue.go +++ /dev/null @@ -1,176 +0,0 @@ -package common - -import ( - "container/heap" - "context" - "errors" - "sync" - "sync/atomic" - "time" -) - -// Event defines the event structure -type Event struct { - Priority int // Priority: the higher the number, the higher the priority - Data any // Event data - Created int64 // The incremented order in which the event was added to the queue - index int // Internal use by heap to track event position -} - -// eventHeap implements heap.Interface -type eventHeap []*Event - -func (h eventHeap) Len() int { return len(h) } -func (h eventHeap) Less(i, j int) bool { - if h[i].Priority == h[j].Priority { - return h[i].Created < h[j].Created // FIFO for events with the same priority - } - return h[i].Priority > h[j].Priority -} -func (h eventHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i]; h[i].index = i; h[j].index = j } -func (h *eventHeap) Push(x any) { *h = append(*h, x.(*Event)) } -func (h *eventHeap) Pop() any { old := *h; n := len(old); x := old[n-1]; *h = old[0 : n-1]; return x } - -// PriorityQueue represents a thread-safe priority queue -type PriorityQueue struct { - mu sync.Mutex - cond *sync.Cond - events eventHeap - closed bool - capacity int - createdCount int64 -} - -// NewPriorityQueue creates a new priority queue with the specified capacity -// capacity = 0 means no limit on the number of events in the queue -func NewPriorityQueue(capacity int) *PriorityQueue { - q := &PriorityQueue{ - capacity: capacity, - } - q.cond = sync.NewCond(&q.mu) - heap.Init(&q.events) - return q -} - -// Push adds an event to the queue -func (q *PriorityQueue) Push(event *Event) error { - q.mu.Lock() - defer q.mu.Unlock() - - if q.closed { - return errors.New("priority queue closed") - } - if q.capacity > 0 && len(q.events) >= q.capacity { - return errors.New("priority queue is full") - } - - event.Created = atomic.AddInt64(&q.createdCount, 1) - - heap.Push(&q.events, event) - q.cond.Signal() - return nil -} - -func (q *PriorityQueue) PushWithContext(ctx context.Context, event *Event) error { - q.mu.Lock() - defer q.mu.Unlock() - - for { - if q.closed { - return errors.New("priority queue closed") - } - if q.capacity == 0 || len(q.events) < q.capacity { - event.Created = atomic.AddInt64(&q.createdCount, 1) - heap.Push(&q.events, event) - q.cond.Signal() - return nil - } - - timer := time.AfterFunc(50*time.Millisecond, func() { - q.cond.Signal() // Wake up periodically - }) - q.cond.Wait() - timer.Stop() - - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - } -} - -// UpdatePriority updates the priority of an event and reorders the heap -func (q *PriorityQueue) UpdatePriority(event *Event, newPriority int) error { - q.mu.Lock() - defer q.mu.Unlock() - - if q.closed { - return errors.New("priority queue closed") - } - - if event.index < 0 || event.index >= len(q.events) { - return errors.New("invalid event index") - } - - // Update the event's priority - event.Priority = newPriority - // Re-heapify the queue to maintain the correct order - heap.Fix(&q.events, event.index) - q.cond.Broadcast() - return nil -} - -// PopWithContext removes and returns the highest-priority event, with context cancellation support -func (q *PriorityQueue) PopWithContext(ctx context.Context) (*Event, error) { - q.mu.Lock() - defer q.mu.Unlock() - - for len(q.events) == 0 && !q.closed { - // Wait for an event to be pushed into the queue, but check if context is canceled - done := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - q.mu.Lock() - q.cond.Signal() - q.mu.Unlock() - case <-done: - } - }() - q.cond.Wait() - close(done) - - if ctx.Err() != nil { - return nil, ctx.Err() - } - } - - if q.closed && len(q.events) == 0 { - return nil, errors.New("priority queue closed") - } - return heap.Pop(&q.events).(*Event), nil -} - -// Close closes the priority queue, preventing any further operations -func (q *PriorityQueue) Close() { - q.mu.Lock() - defer q.mu.Unlock() - - q.closed = true - q.cond.Broadcast() -} - -// Len returns the current length of the queue -func (q *PriorityQueue) Len() int { - q.mu.Lock() - defer q.mu.Unlock() - return len(q.events) -} - -// IsClosed returns whether the queue has been closed -func (q *PriorityQueue) IsClosed() bool { - q.mu.Lock() - defer q.mu.Unlock() - return q.closed -} diff --git a/pkg/common/priorityQueue_test.go b/pkg/common/priorityQueue_test.go deleted file mode 100644 index b68c921f5..000000000 --- a/pkg/common/priorityQueue_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package common - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestPriorityQueue_PushAndBlockingPop(t *testing.T) { - q := NewPriorityQueue(0) - - _ = q.Push(&Event{Priority: 1, Data: "low1"}) - _ = q.Push(&Event{Priority: 1, Data: "low2"}) - _ = q.Push(&Event{Priority: 10, Data: "high1"}) - _ = q.Push(&Event{Priority: 12, Data: "high2"}) - _ = q.Push(&Event{Priority: 1, Data: "low3"}) - _ = q.Push(&Event{Priority: 9, Data: "mid"}) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - for { - event, err := q.PopWithContext(ctx) - if err != nil { - t.Logf("Exit pop loop, reason: %v", err) - break - } - t.Logf("Got event: priority=%d, data=%v", event.Priority, event.Data) - } -} - -func TestPriorityQueue_FIFOOrder(t *testing.T) { - q := NewPriorityQueue(0) - - _ = q.Push(&Event{Priority: 5, Data: "first"}) - _ = q.Push(&Event{Priority: 5, Data: "second"}) - _ = q.Push(&Event{Priority: 5, Data: "third"}) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - e1, _ := q.PopWithContext(ctx) - e2, _ := q.PopWithContext(ctx) - e3, _ := q.PopWithContext(ctx) - - assert.Equal(t, "first", e1.Data) - assert.Equal(t, "second", e2.Data) - assert.Equal(t, "third", e3.Data) -} - -func TestPriorityQueue_UpdatePriority(t *testing.T) { - q := NewPriorityQueue(0) - - e1 := &Event{Priority: 1, Data: "low"} - e2 := &Event{Priority: 5, Data: "mid"} - _ = q.Push(e1) - _ = q.Push(e2) - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - // Increase the priority of a low-priority event - err := q.UpdatePriority(e1, 10) - assert.NoError(t, err) - - // Now e1 should come out first - event, _ := q.PopWithContext(ctx) - assert.Equal(t, "low", event.Data) - - event, _ = q.PopWithContext(ctx) - assert.Equal(t, "mid", event.Data) -} - -func TestPriorityQueue_ContextCancel(t *testing.T) { - q := NewPriorityQueue(0) - - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) - defer cancel() - - // No data, should exit on context timeout - event, err := q.PopWithContext(ctx) - assert.Nil(t, event) - assert.ErrorIs(t, err, context.DeadlineExceeded) -} - -func TestPriorityQueue_Close(t *testing.T) { - q := NewPriorityQueue(0) - - _ = q.Push(&Event{Priority: 1, Data: "data"}) - q.Close() - - assert.True(t, q.IsClosed()) - - // Subsequent push should fail - err := q.Push(&Event{Priority: 2, Data: "should fail"}) - assert.Error(t, err) - - // Pop should work, but after that, it should fail - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - - event, err := q.PopWithContext(ctx) - assert.NoError(t, err) - assert.Equal(t, "data", event.Data) - - event, err = q.PopWithContext(ctx) - assert.Nil(t, event) - assert.Error(t, err) -} diff --git a/pkg/common/trigger_channel.go b/pkg/common/trigger_channel.go index 5a75c74a8..414564574 100644 --- a/pkg/common/trigger_channel.go +++ b/pkg/common/trigger_channel.go @@ -19,11 +19,11 @@ import ( "errors" "fmt" "runtime" + "runtime/debug" "time" "github.com/openimsdk/openim-sdk-core/v3/pkg/constant" "github.com/openimsdk/openim-sdk-core/v3/sdk_struct" - "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/log" ) @@ -34,23 +34,6 @@ var ( ErrTimeout = errors.New("send cmd timeout") ) -// CmdPriorityMap centralized priority definition -var CmdPriorityMap = map[string]int{ - constant.CmdNewMsgCome: 5, - constant.CmdUpdateConversation: 4, - constant.CmdMsgSyncInReinstall: 1, - constant.CmdNotification: 1, - constant.CmdSyncFlag: 1, - constant.CmdSyncData: 1, - constant.CmdUpdateMessage: 1, - - constant.CmdLogOut: 1, - constant.CmdPushMsg: 1, - constant.CmdIMMessageSync: 1, - constant.CmdConnSuccesss: 1, - constant.CmdWakeUpDataSync: 1, -} - // Cmd2Value holds a dispatched command. type Cmd2Value struct { Cmd string @@ -59,63 +42,57 @@ type Cmd2Value struct { Ctx context.Context } -func DispatchCmd(ctx context.Context, cmd string, val any, queue *EventQueue) error { +func DispatchCmd(ctx context.Context, cmd string, val any, queue chan Cmd2Value) error { c2v := Cmd2Value{Cmd: cmd, Value: val, Ctx: ctx} - return sendCmdToQueue(ctx, queue, c2v, timeout) + return sendCmdToChan(queue, c2v, timeout) } -func DispatchUpdateConversation(ctx context.Context, node UpdateConNode, queue *EventQueue) error { +func DispatchUpdateConversation(ctx context.Context, node UpdateConNode, queue chan Cmd2Value) error { return DispatchCmd(ctx, constant.CmdUpdateConversation, node, queue) } -func DispatchUpdateMessage(ctx context.Context, node UpdateMessageNode, queue *EventQueue) error { +func DispatchUpdateMessage(ctx context.Context, node UpdateMessageNode, queue chan Cmd2Value) error { return DispatchCmd(ctx, constant.CmdUpdateMessage, node, queue) } -func DispatchNewMessage(ctx context.Context, msg sdk_struct.CmdNewMsgComeToConversation, queue *EventQueue) error { +func DispatchNewMessage(ctx context.Context, msg sdk_struct.CmdNewMsgComeToConversation, queue chan Cmd2Value) error { return DispatchCmd(ctx, constant.CmdNewMsgCome, msg, queue) } -func DispatchMsgSyncInReinstall(ctx context.Context, msg sdk_struct.CmdMsgSyncInReinstall, queue *EventQueue) error { +func DispatchMsgSyncInReinstall(ctx context.Context, msg sdk_struct.CmdMsgSyncInReinstall, queue chan Cmd2Value) error { return DispatchCmd(ctx, constant.CmdMsgSyncInReinstall, msg, queue) } -func DispatchNotification(ctx context.Context, msg sdk_struct.CmdNewMsgComeToConversation, queue *EventQueue) { +func DispatchNotification(ctx context.Context, msg sdk_struct.CmdNewMsgComeToConversation, queue chan Cmd2Value) { _ = DispatchCmd(ctx, constant.CmdNotification, msg, queue) } -func DispatchSyncFlag(ctx context.Context, syncFlag int, queue *EventQueue) { +func DispatchSyncFlag(ctx context.Context, syncFlag int, queue chan Cmd2Value) { _ = DispatchCmd(ctx, constant.CmdSyncFlag, sdk_struct.CmdNewMsgComeToConversation{SyncFlag: syncFlag}, queue) } -func DispatchSyncFlagWithMeta(ctx context.Context, syncFlag int, seqs map[string]*msg.Seqs, queue *EventQueue) { - _ = DispatchCmd(ctx, constant.CmdSyncFlag, sdk_struct.CmdNewMsgComeToConversation{Seqs: seqs, SyncFlag: syncFlag}, queue) -} - -func DispatchSyncData(ctx context.Context, queue *EventQueue) { +func DispatchSyncData(ctx context.Context, queue chan Cmd2Value) { _ = DispatchCmd(ctx, constant.CmdSyncData, nil, queue) } -// Legacy channel-based dispatchers - -func DispatchPushMsg(ctx context.Context, msg *sdkws.PushMessages, ch chan Cmd2Value) error { - return sendCmdToChan(ch, Cmd2Value{Cmd: constant.CmdPushMsg, Value: msg, Ctx: ctx}, timeout) +func DispatchPushMsg(ctx context.Context, msg *sdkws.PushMessages, queue chan Cmd2Value) error { + return DispatchCmd(ctx, constant.CmdPushMsg, msg, queue) } -func DispatchLogout(ctx context.Context, ch chan Cmd2Value) error { - return sendCmdToChan(ch, Cmd2Value{Cmd: constant.CmdLogOut, Ctx: ctx}, timeout) +func DispatchLogout(ctx context.Context, queue chan Cmd2Value) error { + return DispatchCmd(ctx, constant.CmdLogOut, nil, queue) } -func DispatchConnected(ctx context.Context, ch chan Cmd2Value) error { - return sendCmdToChan(ch, Cmd2Value{Cmd: constant.CmdConnSuccesss, Ctx: ctx}, timeout) +func DispatchConnected(ctx context.Context, queue chan Cmd2Value) error { + return DispatchCmd(ctx, constant.CmdConnSuccesss, nil, queue) } -func DispatchWakeUp(ctx context.Context, ch chan Cmd2Value) error { - return sendCmdToChan(ch, Cmd2Value{Cmd: constant.CmdWakeUpDataSync, Ctx: ctx}, timeout) +func DispatchWakeUp(ctx context.Context, queue chan Cmd2Value) error { + return DispatchCmd(ctx, constant.CmdWakeUpDataSync, nil, queue) } -func DispatchIMSync(ctx context.Context, conversationIDs []string, ch chan Cmd2Value) error { - return sendCmdToChan(ch, Cmd2Value{Cmd: constant.CmdIMMessageSync, Value: conversationIDs, Ctx: ctx}, timeout) +func DispatchIMSync(ctx context.Context, conversationIDs []string, queue chan Cmd2Value) error { + return DispatchCmd(ctx, constant.CmdIMMessageSync, conversationIDs, queue) } type DeleteConNode struct { @@ -179,27 +156,6 @@ func sendCmdToChan(ch chan<- Cmd2Value, value Cmd2Value, timeout time.Duration) } } -// General send logic for event queue. -func sendCmdToQueue(ctx context.Context, queue *EventQueue, value Cmd2Value, timeout time.Duration) error { - if value.Caller == "" { - value.Caller = GetCaller(4) - } - - priority, ok := CmdPriorityMap[value.Cmd] - if !ok { - priority = 1 // default - } - ctxWithTimeout, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - _, err := queue.ProduceWithContext(ctxWithTimeout, value, priority) - if err != nil { - log.ZError(ctx, "sendCmd queue produce error", err, "caller", value.Caller, "cmd", value.Cmd, "value", value.Value) - return err - } - log.ZInfo(ctx, "sendCmd queue produce success", "caller", value.Caller, "cmd", value.Cmd, "value", value.Value) - return nil -} - // GetCaller returns the function and line number func GetCaller(skip int) string { pc, _, line, ok := runtime.Caller(skip) @@ -209,3 +165,29 @@ func GetCaller(skip int) string { name := runtime.FuncForPC(pc).Name() return fmt.Sprintf("%s:%d", name, line) } + +type goroutine interface { + Work(cmd Cmd2Value) + GetCh() chan Cmd2Value +} + +func DoListener(ctx context.Context, li goroutine) { + defer func() { + if r := recover(); r != nil { + err := fmt.Sprintf("panic: %+v\n%s", r, debug.Stack()) + log.ZWarn(ctx, "DoListener panic", nil, "panic info", err) + } + }() + + for { + select { + case cmd := <-li.GetCh(): + log.ZInfo(cmd.Ctx, "recv cmd", "caller", cmd.Caller, "cmd", cmd.Cmd, "value", cmd.Value) + li.Work(cmd) + log.ZInfo(cmd.Ctx, "done cmd", "caller", cmd.Caller, "cmd", cmd.Cmd, "value", cmd.Value) + case <-ctx.Done(): + log.ZInfo(ctx, "conversation done sdk logout.....") + return + } + } +} diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 70b8e7868..a07fe8f1e 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -241,16 +241,12 @@ const ( const BigVersion = "v3" const ( - MsgSyncBegin = 1001 // - MsgSyncData = 1002 // - MsgSyncEnd = 1003 // - MsgSyncFailed = 1004 - AppDataSyncBegin = 1005 - AppDataSyncData = 1006 - AppDataSyncEnd = 1007 - LargeDataSyncBegin = 1008 - LargeDataSyncData = 1009 - LargeDataSyncEnd = 1010 + MsgSyncBegin = 1001 // + MsgSyncProcessing = 1002 // + MsgSyncEnd = 1003 // + MsgSyncFailed = 1004 + AppDataSyncStart = 1005 + AppDataSyncFinish = 1006 ) const ( diff --git a/pkg/sort_conversation/sort_conversation.go b/pkg/sort_conversation/sort_conversation.go deleted file mode 100644 index da82fc2dc..000000000 --- a/pkg/sort_conversation/sort_conversation.go +++ /dev/null @@ -1,218 +0,0 @@ -package sort_conversation - -import ( - "context" - "sort" - "strings" - - "github.com/openimsdk/tools/utils/datautil" -) - -type ConversationMetaData struct { - ConversationID string - IsPinned bool - LatestMsgSendTime int64 - DraftTextTime int64 -} - -type SortConversationList struct { - conversations []*ConversationMetaData - pinnedConversationIDs map[string]struct{} - conversationIndex map[string]int -} - -func NewSortConversationList(list []*ConversationMetaData, pinnedIDs []string) *SortConversationList { - s := &SortConversationList{ - pinnedConversationIDs: datautil.SliceSetAny(pinnedIDs, func(e string) string { - return e - }), - conversationIndex: make(map[string]int), - } - s.conversations = list - sort.Slice(s.conversations, func(i, j int) bool { - return s.compareConversations(s.conversations[i], s.conversations[j]) - }) - s.refreshIndex() - return s -} - -// InsertOrUpdate inserts or updates a conversation, updating its LatestMsgSendTime / DraftTime / pinned status (all fields are passed in) -func (l *SortConversationList) InsertOrUpdate(c *ConversationMetaData) { - if c.IsPinned { - l.pinnedConversationIDs[c.ConversationID] = struct{}{} - } else { - delete(l.pinnedConversationIDs, c.ConversationID) - } - if idx, exists := l.conversationIndex[c.ConversationID]; exists { - l.conversations = append(l.conversations[:idx], l.conversations[idx+1:]...) - } - idx := l.findInsertIndex(c) - l.conversations = append(l.conversations, nil) - copy(l.conversations[idx+1:], l.conversations[idx:]) - l.conversations[idx] = c - l.refreshIndex() -} - -// Delete removes a conversation -func (l *SortConversationList) Delete(conversationID string) { - idx, exists := l.conversationIndex[conversationID] - if !exists { - return - } - l.conversations = append(l.conversations[:idx], l.conversations[idx+1:]...) - delete(l.pinnedConversationIDs, conversationID) - l.refreshIndex() -} - -// Top returns the top N conversations -func (l *SortConversationList) Top(limit int) []*ConversationMetaData { - if limit > 0 && len(l.conversations) > limit { - return l.conversations[:limit] - } - return l.conversations -} - -// After gets the N conversations after a specific conversation -func (l *SortConversationList) After(conversationID string, n int) []*ConversationMetaData { - idx, exists := l.conversationIndex[conversationID] - if !exists { - return nil - } - start := idx + 1 - end := start + n - if end > len(l.conversations) { - end = len(l.conversations) - } - return l.conversations[start:end] -} - -// All returns all conversations -func (l *SortConversationList) All() []*ConversationMetaData { - return l.conversations -} - -// Internal functions - -func (l *SortConversationList) findInsertIndex(c *ConversationMetaData) int { - for i, exist := range l.conversations { - if l.compareConversations(c, exist) { - return i - } - } - return len(l.conversations) -} - -func (l *SortConversationList) refreshIndex() { - l.conversationIndex = make(map[string]int) - for i, c := range l.conversations { - l.conversationIndex[c.ConversationID] = i - } -} - -func (l *SortConversationList) compareConversations(a, b *ConversationMetaData) bool { - _, ap := l.pinnedConversationIDs[a.ConversationID] - _, bp := l.pinnedConversationIDs[b.ConversationID] - if ap != bp { - return ap // pinned conversations come first - } - at, bt := l.getEffectiveTime(a), l.getEffectiveTime(b) - return at > bt -} - -func (l *SortConversationList) getEffectiveTime(c *ConversationMetaData) int64 { - if c.DraftTextTime > c.LatestMsgSendTime { - return c.DraftTextTime - } - return c.LatestMsgSendTime -} - -func (l *SortConversationList) NewIterator() *SortConversationIterator { - return &SortConversationIterator{ - list: l, - cursor: 0, - } -} - -type SortConversationIterator struct { - list *SortConversationList - cursor int -} - -// NextTop returns the next batch of size conversations -func (it *SortConversationIterator) NextTop(size int) []*ConversationMetaData { - if it.cursor >= len(it.list.conversations) { - return nil - } - end := it.cursor + size - if end > len(it.list.conversations) { - end = len(it.list.conversations) - } - batch := it.list.conversations[it.cursor:end] - it.cursor = end - return batch -} - -type BatchHandler func(ctx context.Context, batchID int, needSyncSeqMap map[string][2]int64, isFirst bool) - -type ConversationBatchProcessor struct { - iter *SortConversationIterator - needSyncSeqMap map[string][2]int64 - isFirst bool - batchSize int - batchID int -} - -func NewConversationBatchProcessor(list *SortConversationList, needSyncSeqMap map[string][2]int64, batchSize int) *ConversationBatchProcessor { - return &ConversationBatchProcessor{ - iter: list.NewIterator(), - needSyncSeqMap: needSyncSeqMap, - batchSize: batchSize, - isFirst: true, - batchID: 1, - } -} - -func (p *ConversationBatchProcessor) Run(ctx context.Context, handler BatchHandler) { - result := make(map[string][2]int64) - - for { - batch := p.iter.NextTop(p.batchSize) - if len(batch) == 0 { - break - } - - for _, conv := range batch { - if v, ok := p.needSyncSeqMap[conv.ConversationID]; ok { - result[conv.ConversationID] = v - } - notificationID := GetNotificationConversationIDByConversationID(conv.ConversationID) - if v, ok := p.needSyncSeqMap[notificationID]; ok { - result[notificationID] = v - } - - if len(result) >= p.batchSize { - p.emitResult(ctx, handler, result) - result = make(map[string][2]int64) - } - } - } - - if len(result) > 0 { - p.emitResult(ctx, handler, result) - } -} - -func (p *ConversationBatchProcessor) emitResult(ctx context.Context, handler BatchHandler, result map[string][2]int64) { - handler(ctx, p.batchID, result, p.isFirst) - p.batchID++ - p.isFirst = false -} - -func GetNotificationConversationIDByConversationID(conversationID string) string { - l := strings.Split(conversationID, "_") - if len(l) > 1 { - l[0] = "n" - return strings.Join(l, "_") - } - return "" -} From c89da8120050a2dc97da6f86012f096ee4d0906a Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 4 Jun 2025 18:12:31 +0800 Subject: [PATCH 09/11] refactor: change sync strategy of group request and friend request. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/group/server_api.go | 18 ++++++++++++++++-- internal/relation/server_api.go | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/internal/group/server_api.go b/internal/group/server_api.go index 9b36e0a56..abb670277 100644 --- a/internal/group/server_api.go +++ b/internal/group/server_api.go @@ -82,7 +82,14 @@ func (g *Group) getServerSelfGroupApplication(ctx context.Context, groupIDs []st handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.GroupRequest, error) { req := &group.GetUserReqApplicationListReq{UserID: g.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, GroupIDs: groupIDs, HandleResults: handleResults} - return api.Page(ctx, req, api.GetSendGroupApplicationList.Invoke, (*group.GetUserReqApplicationListResp).GetGroupRequests) + if showNumber <= 0 { + return api.Page(ctx, req, api.GetSendGroupApplicationList.Invoke, (*group.GetUserReqApplicationListResp).GetGroupRequests) + } + resp, err := api.GetSendGroupApplicationList.Invoke(ctx, req) + if err != nil { + return nil, err + } + return resp.GetGroupRequests(), nil } func (g *Group) getServerJoinGroup(ctx context.Context) ([]*sdkws.GroupInfo, error) { @@ -94,7 +101,14 @@ func (g *Group) getServerAdminGroupApplicationList(ctx context.Context, groupIDs handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.GroupRequest, error) { req := &group.GetGroupApplicationListReq{FromUserID: g.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, GroupIDs: groupIDs, HandleResults: handleResults} - return api.Page(ctx, req, api.GetRecvGroupApplicationList.Invoke, (*group.GetGroupApplicationListResp).GetGroupRequests) + if showNumber <= 0 { + return api.Page(ctx, req, api.GetRecvGroupApplicationList.Invoke, (*group.GetGroupApplicationListResp).GetGroupRequests) + } + resp, err := api.GetRecvGroupApplicationList.Invoke(ctx, req) + if err != nil { + return nil, err + } + return resp.GetGroupRequests(), nil } func (g *Group) getGroupsInfoFromServer(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) { diff --git a/internal/relation/server_api.go b/internal/relation/server_api.go index 83a7f393c..018e1966f 100644 --- a/internal/relation/server_api.go +++ b/internal/relation/server_api.go @@ -14,13 +14,27 @@ func (r *Relation) getDesignatedFriendsApply(ctx context.Context, req *relation. func (r *Relation) getSelfFriendApplicationList(ctx context.Context, pageNumber, showNumber int32) ([]*sdkws.FriendRequest, error) { req := &relation.GetPaginationFriendsApplyFromReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}} - return api.Page(ctx, req, api.GetSelfFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyFromResp).GetFriendRequests) + if showNumber <= 0 { + return api.Page(ctx, req, api.GetSelfFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyFromResp).GetFriendRequests) + } + resp, err := api.GetSelfFriendApplicationList.Invoke(ctx, req) + if err != nil { + return nil, err + } + return resp.GetFriendRequests(), nil } func (r *Relation) getRecvFriendApplicationList(ctx context.Context, handleResults []int32, pageNumber, showNumber int32) ([]*sdkws.FriendRequest, error) { req := &relation.GetPaginationFriendsApplyToReq{UserID: r.loginUserID, Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}, HandleResults: handleResults} - return api.Page(ctx, req, api.GetRecvFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyToResp).GetFriendRequests) + if showNumber <= 0 { + return api.Page(ctx, req, api.GetRecvFriendApplicationList.Invoke, (*relation.GetPaginationFriendsApplyToResp).GetFriendRequests) + } + resp, err := api.GetRecvFriendApplicationList.Invoke(ctx, req) + if err != nil { + return nil, err + } + return resp.GetFriendRequests(), nil } func (r *Relation) getBlackList(ctx context.Context) ([]*sdkws.BlackInfo, error) { From 132f9e080ac64c203e6f7741593721dfd734de3c Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:08:37 +0800 Subject: [PATCH 10/11] refactor: change sync strategy of group request and friend request. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/relation/notification.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/relation/notification.go b/internal/relation/notification.go index 02f17dded..a6a6c079f 100644 --- a/internal/relation/notification.go +++ b/internal/relation/notification.go @@ -33,7 +33,9 @@ func (r *Relation) doNotification(ctx context.Context, msg *sdkws.MsgData) error if err != nil { return err } - r.friendshipListener.OnFriendApplicationAccepted(*ServerFriendRequestToLocalFriendRequest(tips.Request)) + if tips.Request != nil { + r.friendshipListener.OnFriendApplicationAccepted(*ServerFriendRequestToLocalFriendRequest(tips.Request)) + } return r.IncrSyncFriends(ctx) case constant.FriendApplicationRejectedNotification: var tips sdkws.FriendApplicationRejectedTips From 7a47d6358f6942309e3a72e514a1a65878f8975c Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:17:18 +0800 Subject: [PATCH 11/11] fix: group member request trigger error. Signed-off-by: Gordon <46924906+FGadvancer@users.noreply.github.com> --- internal/group/notification.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/group/notification.go b/internal/group/notification.go index d9931dd9e..c64cec02e 100644 --- a/internal/group/notification.go +++ b/internal/group/notification.go @@ -65,7 +65,7 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { return err } if g.filter.ShouldExecute(detail.Uuid) { - g.listener().OnGroupMemberAdded(utils.StructToJsonString( + g.listener().OnGroupApplicationAdded(utils.StructToJsonString( ServerGroupRequestToLocalGroupRequestForNotification(detail.GetGroup(), detail.GetRequest()))) } default: