package jssdk import ( "context" "github.com/gin-gonic/gin" "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/jssdk" "github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/utils/datautil" "sort" ) const ( maxGetActiveConversation = 500 defaultGetActiveConversation = 100 ) func NewJSSdkApi(user user.UserClient, friend relation.FriendClient, group group.GroupClient, msg msg.MsgClient, conv conversation.ConversationClient) *JSSdk { return &JSSdk{ user: user, friend: friend, group: group, msg: msg, conv: conv, } } type JSSdk struct { user user.UserClient friend relation.FriendClient group group.GroupClient msg msg.MsgClient conv conversation.ConversationClient } 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 := field(ctx, x.user.GetDesignateUsers, &user.GetDesignateUsersReq{UserIDs: userIDs}, (*user.GetDesignateUsersResp).GetUsersInfo) if err != nil { return err } friends, err := field(ctx, x.friend.GetFriendInfo, &relation.GetFriendInfoReq{OwnerUserID: conversations[0].Conversation.OwnerUserID, FriendUserIDs: userIDs}, (*relation.GetFriendInfoResp).GetFriendInfos) if err != nil { return err } userMap = datautil.SliceToMap(users, (*sdkws.UserInfo).GetUserID) friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID) } if len(groupIDs) > 0 { resp, err := x.group.GetGroupsInfo(ctx, &group.GetGroupsInfoReq{GroupIDs: groupIDs}) if err != nil { return err } groupMap = datautil.SliceToMap(resp.GroupInfos, (*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 := field(ctx, x.conv.GetConversationIDs, &conversation.GetConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs) if err != nil { return nil, err } if len(conversationIDs) == 0 { return &jssdk.GetActiveConversationsResp{}, nil } readSeq, err := field(ctx, x.msg.GetHasReadSeqs, &msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs) if err != nil { return nil, err } activeConversation, err := field(ctx, x.msg.GetActiveConversation, &msg.GetActiveConversationReq{ConversationIDs: conversationIDs}, (*msg.GetActiveConversationResp).GetConversations) if err != nil { return nil, err } if len(activeConversation) == 0 { return &jssdk.GetActiveConversationsResp{}, nil } sortConversations := sortActiveConversations{ Conversation: activeConversation, } if len(activeConversation) > 1 { pinnedConversationIDs, err := field(ctx, x.conv.GetPinnedConversationIDs, &conversation.GetPinnedConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs) if err != nil { return nil, err } sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs) } sort.Sort(&sortConversations) sortList := sortConversations.Top(int(req.Count)) conversations, err := field(ctx, x.conv.GetConversations, &conversation.GetConversationsReq{ OwnerUserID: req.OwnerUserID, ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string { return c.ConversationID })}, (*conversation.GetConversationsResp).GetConversations) if err != nil { return nil, err } msgs, err := field(ctx, x.msg.GetSeqMessage, &msg.GetSeqMessageReq{ UserID: req.OwnerUserID, Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs { return &msg.ConversationSeqs{ ConversationID: c.ConversationID, Seqs: []int64{c.MaxSeq}, } }), }, (*msg.GetSeqMessageResp).GetMsgs) 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 := field(ctx, x.conv.GetConversations, &conversation.GetConversationsReq{OwnerUserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*conversation.GetConversationsResp).GetConversations) 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 := field(ctx, x.msg.GetMaxSeqs, &msg.GetMaxSeqsReq{ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs) if err != nil { return nil, err } readSeqs, err := field(ctx, x.msg.GetHasReadSeqs, &msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs) 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 = field(ctx, x.msg.GetSeqMessage, &msg.GetSeqMessageReq{UserID: req.OwnerUserID, Conversations: conversationSeqs}, (*msg.GetSeqMessageResp).GetMsgs) 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 }