package jssdk import ( "context" "github.com/openimsdk/open-im-server/v3/pkg/rpcli" "sort" "github.com/gin-gonic/gin" "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/jssdk" "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/utils/datautil" ) const ( maxGetActiveConversation = 500 defaultGetActiveConversation = 100 ) func NewJSSdkApi() *JSSdk { return &JSSdk{} } type JSSdk struct { userClient rpcli.UserClient relationClient rpcli.RelationClient groupClient rpcli.GroupClient conversationClient rpcli.ConversationClient msgClient rpcli.MsgClient } func (x *JSSdk) GetActiveConversations(c *gin.Context) { call(c, x.getActiveConversations) } func (x *JSSdk) GetConversations(c *gin.Context) { call(c, x.getConversations) } func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.ConversationMsg) error { if len(conversations) == 0 { return nil } var ( userIDs []string groupIDs []string ) for _, c := range conversations { if c.Conversation.GroupID == "" { userIDs = append(userIDs, c.Conversation.UserID) } else { groupIDs = append(groupIDs, c.Conversation.GroupID) } } var ( userMap map[string]*sdkws.UserInfo friendMap map[string]*relation.FriendInfoOnly groupMap map[string]*sdkws.GroupInfo ) if len(userIDs) > 0 { users, err := x.userClient.GetUsersInfo(ctx, userIDs) if err != nil { return err } friends, err := x.relationClient.GetFriendsInfo(ctx, conversations[0].Conversation.OwnerUserID, userIDs) if err != nil { return err } userMap = datautil.SliceToMap(users, (*sdkws.UserInfo).GetUserID) friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID) } if len(groupIDs) > 0 { groups, err := x.groupClient.GetGroupsInfo(ctx, groupIDs) if err != nil { return err } groupMap = datautil.SliceToMap(groups, (*sdkws.GroupInfo).GetGroupID) } for _, c := range conversations { if c.Conversation.GroupID == "" { c.User = userMap[c.Conversation.UserID] c.Friend = friendMap[c.Conversation.UserID] } else { c.Group = groupMap[c.Conversation.GroupID] } } return nil } func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActiveConversationsReq) (*jssdk.GetActiveConversationsResp, error) { if req.Count <= 0 || req.Count > maxGetActiveConversation { req.Count = defaultGetActiveConversation } req.OwnerUserID = mcontext.GetOpUserID(ctx) conversationIDs, err := x.conversationClient.GetConversationIDs(ctx, req.OwnerUserID) if err != nil { return nil, err } if len(conversationIDs) == 0 { return &jssdk.GetActiveConversationsResp{}, nil } readSeq, err := x.msgClient.GetHasReadSeqs(ctx, conversationIDs, req.OwnerUserID) if err != nil { return nil, err } activeConversation, err := x.msgClient.GetActiveConversation(ctx, conversationIDs) if err != nil { return nil, err } if len(activeConversation) == 0 { return &jssdk.GetActiveConversationsResp{}, nil } sortConversations := sortActiveConversations{ Conversation: activeConversation, } if len(activeConversation) > 1 { pinnedConversationIDs, err := x.conversationClient.GetPinnedConversationIDs(ctx, req.OwnerUserID) if err != nil { return nil, err } sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs) } sort.Sort(&sortConversations) sortList := sortConversations.Top(int(req.Count)) conversations, err := x.conversationClient.GetConversations(ctx, datautil.Slice(sortList, func(c *msg.ActiveConversation) string { return c.ConversationID }), req.OwnerUserID) if err != nil { return nil, err } msgs, err := x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs { return &msg.ConversationSeqs{ ConversationID: c.ConversationID, Seqs: []int64{c.MaxSeq}, } })) if err != nil { return nil, err } conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string { return c.ConversationID }) resp := make([]*jssdk.ConversationMsg, 0, len(sortList)) for _, c := range sortList { conv, ok := conversationMap[c.ConversationID] if !ok { continue } var lastMsg *sdkws.MsgData if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 { lastMsg = msgList.Msgs[0] } resp = append(resp, &jssdk.ConversationMsg{ Conversation: conv, LastMsg: lastMsg, MaxSeq: c.MaxSeq, ReadSeq: readSeq[c.ConversationID], }) } if err := x.fillConversations(ctx, resp); err != nil { return nil, err } var unreadCount int64 for _, c := range activeConversation { count := c.MaxSeq - readSeq[c.ConversationID] if count > 0 { unreadCount += count } } return &jssdk.GetActiveConversationsResp{ Conversations: resp, UnreadCount: unreadCount, }, nil } func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) { req.OwnerUserID = mcontext.GetOpUserID(ctx) conversations, err := x.conversationClient.GetConversations(ctx, req.ConversationIDs, req.OwnerUserID) if err != nil { return nil, err } if len(conversations) == 0 { return &jssdk.GetConversationsResp{}, nil } req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string { return c.ConversationID }) maxSeqs, err := x.msgClient.GetMaxSeqs(ctx, req.ConversationIDs) if err != nil { return nil, err } readSeqs, err := x.msgClient.GetHasReadSeqs(ctx, req.ConversationIDs, req.OwnerUserID) if err != nil { return nil, err } conversationSeqs := make([]*msg.ConversationSeqs, 0, len(conversations)) for _, c := range conversations { if seq := maxSeqs[c.ConversationID]; seq > 0 { conversationSeqs = append(conversationSeqs, &msg.ConversationSeqs{ ConversationID: c.ConversationID, Seqs: []int64{seq}, }) } } var msgs map[string]*sdkws.PullMsgs if len(conversationSeqs) > 0 { msgs, err = x.msgClient.GetSeqMessage(ctx, req.OwnerUserID, conversationSeqs) if err != nil { return nil, err } } resp := make([]*jssdk.ConversationMsg, 0, len(conversations)) for _, c := range conversations { var lastMsg *sdkws.MsgData if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 { lastMsg = msgList.Msgs[0] } resp = append(resp, &jssdk.ConversationMsg{ Conversation: c, LastMsg: lastMsg, MaxSeq: maxSeqs[c.ConversationID], ReadSeq: readSeqs[c.ConversationID], }) } if err := x.fillConversations(ctx, resp); err != nil { return nil, err } var unreadCount int64 for conversationID, maxSeq := range maxSeqs { count := maxSeq - readSeqs[conversationID] if count > 0 { unreadCount += count } } return &jssdk.GetConversationsResp{ Conversations: resp, UnreadCount: unreadCount, }, nil }