diff --git a/go.mod b/go.mod index fbaa19434..deef21813 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/openimsdk/protocol v0.0.73-alpha.6 + github.com/openimsdk/protocol v0.0.73-alpha.7 github.com/openimsdk/tools v0.0.50-alpha.79 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 @@ -34,7 +34,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/kelindar/bitmap v1.5.2 github.com/likexian/gokit v0.25.13 - github.com/openimsdk/gomake v0.0.15-alpha.2 + github.com/openimsdk/gomake v0.0.15-alpha.5 github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil v3.21.11+incompatible diff --git a/go.sum b/go.sum index 390a51c4a..014747168 100644 --- a/go.sum +++ b/go.sum @@ -345,10 +345,10 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/openimsdk/gomake v0.0.15-alpha.2 h1:5Q8yl8ezy2yx+q8/ucU/t4kJnDfCzNOrkXcDACCqtyM= -github.com/openimsdk/gomake v0.0.15-alpha.2/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/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/gomake v0.0.15-alpha.5 h1:eEZCEHm+NsmcO3onXZPIUbGFCYPYbsX5beV3ZyOsGhY= +github.com/openimsdk/gomake v0.0.15-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= +github.com/openimsdk/protocol v0.0.73-alpha.7 h1:Kr/xc3ZKruHlKLUFBGDWLe8Fwh3AoSm55XPryyCI0NE= +github.com/openimsdk/protocol v0.0.73-alpha.7/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= github.com/openimsdk/tools v0.0.50-alpha.79 h1:jxYEbrzaze4Z2r4NrKad816buZ690ix0L9MTOOOH3ik= github.com/openimsdk/tools v0.0.50-alpha.79/go.mod h1:n2poR3asX1e1XZce4O+MOWAp+X02QJRFvhcLCXZdzRo= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= diff --git a/internal/api/msg.go b/internal/api/msg.go index 090f3329b..4de299a75 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -551,3 +551,11 @@ func (m *MessageApi) SearchMsg(c *gin.Context) { func (m *MessageApi) GetServerTime(c *gin.Context) { a2r.Call(c, msg.MsgClient.GetServerTime, m.Client) } + +func (m *MessageApi) GetConversationsUnreadCount(c *gin.Context) { + a2r.Call(c, msg.MsgClient.GetConversationsUnreadCount, m.Client) +} + +func (m *MessageApi) ClearConversationsUnreadCount(c *gin.Context) { + a2r.Call(c, msg.MsgClient.ClearConversationsUnreadCount, m.Client) +} diff --git a/internal/api/router.go b/internal/api/router.go index 920bd5366..9ae54fdc2 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -252,6 +252,8 @@ func newGinRouter(ctx context.Context, client discovery.Conn, cfg *Config) (*gin msgGroup.POST("/batch_send_msg", m.BatchSendMsg) msgGroup.POST("/check_msg_is_send_success", m.CheckMsgIsSendSuccess) msgGroup.POST("/get_server_time", m.GetServerTime) + msgGroup.POST("/get_conversations_unread_count", m.GetConversationsUnreadCount) + msgGroup.POST("/clear_conversations_unread_count", m.ClearConversationsUnreadCount) } // Conversation { diff --git a/internal/rpc/msg/unread.go b/internal/rpc/msg/unread.go new file mode 100644 index 000000000..fb5d0c8bb --- /dev/null +++ b/internal/rpc/msg/unread.go @@ -0,0 +1,62 @@ +package msg + +import ( + "context" + + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/msg" +) + +func (m *msgServer) getAndClearUnread(ctx context.Context, userID string, conversationIDs []string, clearCount bool) (map[string]int64, error) { + if err := authverify.CheckAccessV3(ctx, userID, m.config.Share.IMAdminUserID); err != nil { + return nil, err + } + readSeqs, err := m.MsgDatabase.GetHasReadSeqs(ctx, userID, conversationIDs) + if err != nil { + return nil, err + } + maxSeqs, err := m.MsgDatabase.GetMaxSeqs(ctx, conversationIDs) + if err != nil { + return nil, err + } + conversations, err := m.ConversationLocalCache.GetConversations(ctx, userID, conversationIDs) + if err != nil { + return nil, err + } + unreadCount := make(map[string]int64) + for _, conversation := range conversations { + maxSeq := conversation.MaxSeq + if maxSeq == 0 { + maxSeq = maxSeqs[conversation.ConversationID] + } + count := maxSeq - readSeqs[conversation.ConversationID] + if count < 0 { + count = 0 + } + unreadCount[conversation.ConversationID] = count + if count > 0 && clearCount { + if err := m.MsgDatabase.SetHasReadSeq(ctx, userID, conversation.ConversationID, maxSeq); err != nil { + return nil, err + } + m.sendMarkAsReadNotification(ctx, conversation.ConversationID, constant.SingleChatType, userID, userID, nil, maxSeq) + } + } + return unreadCount, nil +} + +func (m *msgServer) GetConversationsUnreadCount(ctx context.Context, req *msg.GetConversationsUnreadCountReq) (*msg.GetConversationsUnreadCountResp, error) { + res, err := m.getAndClearUnread(ctx, req.UserID, req.ConversationIDs, false) + if err != nil { + return nil, err + } + return &msg.GetConversationsUnreadCountResp{UnreadCount: res}, nil +} + +func (m *msgServer) ClearConversationsUnreadCount(ctx context.Context, req *msg.ClearConversationsUnreadCountReq) (*msg.ClearConversationsUnreadCountResp, error) { + res, err := m.getAndClearUnread(ctx, req.UserID, req.ConversationIDs, true) + if err != nil { + return nil, err + } + return &msg.ClearConversationsUnreadCountResp{UnreadCount: res}, nil +}