mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-11-04 11:22:10 +08:00 
			
		
		
		
	feat: provide the interface required by js sdk (#2712)
* fix: GroupApplicationAcceptedNotification * fix: GroupApplicationAcceptedNotification * fix: NotificationUserInfoUpdate * cicd: robot automated Change * fix: component * fix: getConversationInfo * feat: cron task * feat: cron task * feat: cron task * feat: cron task * feat: cron task * fix: minio config url recognition error * update gomake version * update gomake version * fix: seq conversion bug * fix: redis pipe exec * fix: ImportFriends * fix: A large number of logs keysAndValues length is not even * feat: mark read aggregate write * feat: online status supports redis cluster * feat: online status supports redis cluster * feat: online status supports redis cluster * merge * merge * read seq is written to mongo * read seq is written to mongo * fix: invitation to join group notification * fix: friend op_user_id * feat: optimizing asynchronous context * feat: optimizing memamq size * feat: add GetSeqMessage * feat: GroupApplicationAgreeMemberEnterNotification * feat: GroupApplicationAgreeMemberEnterNotification * feat: go.mod * feat: go.mod * feat: join group notification and get seq * feat: join group notification and get seq * feat: avoid pulling messages from sessions with a large number of max seq values of 0 * feat: API supports gzip * go.mod * fix: nil pointer error on close * fix: listen error * fix: listen error * update go.mod * feat: add log * fix: token parse token value * fix: GetMsgBySeqs boundary issues * fix: sn_ not sort * fix: sn_ not sort * fix: sn_ not sort * fix: jssdk add * fix: jssdk support * fix: jssdk support * fix: jssdk support --------- Co-authored-by: withchao <withchao@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									047fa33704
								
							
						
					
					
						commit
						3914dc1435
					
				@ -15,10 +15,9 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	_ "net/http/pprof"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
 | 
						"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
 | 
				
			||||||
	"github.com/openimsdk/tools/system/program"
 | 
						"github.com/openimsdk/tools/system/program"
 | 
				
			||||||
 | 
						_ "net/http/pprof"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -12,7 +12,7 @@ require (
 | 
				
			|||||||
	github.com/gorilla/websocket v1.5.1
 | 
						github.com/gorilla/websocket v1.5.1
 | 
				
			||||||
	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 | 
						github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 | 
				
			||||||
	github.com/mitchellh/mapstructure v1.5.0
 | 
						github.com/mitchellh/mapstructure v1.5.0
 | 
				
			||||||
	github.com/openimsdk/protocol v0.0.72-pre-release-v3.8.2-alpha.5
 | 
						github.com/openimsdk/protocol v0.0.72-alpha.41
 | 
				
			||||||
	github.com/openimsdk/tools v0.0.50-alpha.16
 | 
						github.com/openimsdk/tools v0.0.50-alpha.16
 | 
				
			||||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
						github.com/pkg/errors v0.9.1 // indirect
 | 
				
			||||||
	github.com/prometheus/client_golang v1.18.0
 | 
						github.com/prometheus/client_golang v1.18.0
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -319,8 +319,8 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
 | 
				
			|||||||
github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
 | 
					github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
 | 
				
			||||||
github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
 | 
					github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y=
 | 
				
			||||||
github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
 | 
					github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
 | 
				
			||||||
github.com/openimsdk/protocol v0.0.72-pre-release-v3.8.2-alpha.5 h1:b0JAuBhzIYirHeXp7asB04bE1q+KhU3dpAaAroc/Am0=
 | 
					github.com/openimsdk/protocol v0.0.72-alpha.41 h1:SMMoTc1iu+wtRqUqmIgqPJFejLgPeauOwoJ4VVG4iMQ=
 | 
				
			||||||
github.com/openimsdk/protocol v0.0.72-pre-release-v3.8.2-alpha.5/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
 | 
					github.com/openimsdk/protocol v0.0.72-alpha.41/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
 | 
				
			||||||
github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc=
 | 
					github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc=
 | 
				
			||||||
github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
 | 
					github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
 | 
				
			||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
 | 
					github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,15 @@
 | 
				
			|||||||
package jssdk
 | 
					package jssdk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
	"github.com/openimsdk/protocol/conversation"
 | 
						"github.com/openimsdk/protocol/conversation"
 | 
				
			||||||
 | 
						"github.com/openimsdk/protocol/group"
 | 
				
			||||||
 | 
						"github.com/openimsdk/protocol/jssdk"
 | 
				
			||||||
	"github.com/openimsdk/protocol/msg"
 | 
						"github.com/openimsdk/protocol/msg"
 | 
				
			||||||
 | 
						"github.com/openimsdk/protocol/relation"
 | 
				
			||||||
	"github.com/openimsdk/protocol/sdkws"
 | 
						"github.com/openimsdk/protocol/sdkws"
 | 
				
			||||||
	"github.com/openimsdk/tools/a2r"
 | 
						"github.com/openimsdk/protocol/user"
 | 
				
			||||||
	"github.com/openimsdk/tools/mcontext"
 | 
						"github.com/openimsdk/tools/mcontext"
 | 
				
			||||||
	"github.com/openimsdk/tools/utils/datautil"
 | 
						"github.com/openimsdk/tools/utils/datautil"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@ -16,16 +20,22 @@ const (
 | 
				
			|||||||
	defaultGetActiveConversation = 100
 | 
						defaultGetActiveConversation = 100
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewJSSdkApi(msg msg.MsgClient, conv conversation.ConversationClient) *JSSdk {
 | 
					func NewJSSdkApi(user user.UserClient, friend relation.FriendClient, group group.GroupClient, msg msg.MsgClient, conv conversation.ConversationClient) *JSSdk {
 | 
				
			||||||
	return &JSSdk{
 | 
						return &JSSdk{
 | 
				
			||||||
		msg:  msg,
 | 
							user:   user,
 | 
				
			||||||
		conv: conv,
 | 
							friend: friend,
 | 
				
			||||||
 | 
							group:  group,
 | 
				
			||||||
 | 
							msg:    msg,
 | 
				
			||||||
 | 
							conv:   conv,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type JSSdk struct {
 | 
					type JSSdk struct {
 | 
				
			||||||
	msg  msg.MsgClient
 | 
						user   user.UserClient
 | 
				
			||||||
	conv conversation.ConversationClient
 | 
						friend relation.FriendClient
 | 
				
			||||||
 | 
						group  group.GroupClient
 | 
				
			||||||
 | 
						msg    msg.MsgClient
 | 
				
			||||||
 | 
						conv   conversation.ConversationClient
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *JSSdk) GetActiveConversations(c *gin.Context) {
 | 
					func (x *JSSdk) GetActiveConversations(c *gin.Context) {
 | 
				
			||||||
@ -36,25 +46,71 @@ func (x *JSSdk) GetConversations(c *gin.Context) {
 | 
				
			|||||||
	call(c, x.getConversations)
 | 
						call(c, x.getConversations)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, error) {
 | 
					func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.ConversationMsg) error {
 | 
				
			||||||
	req, err := a2r.ParseRequest[ActiveConversationsReq](ctx)
 | 
						if len(conversations) == 0 {
 | 
				
			||||||
	if err != nil {
 | 
							return nil
 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						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 {
 | 
						if req.Count <= 0 || req.Count > maxGetActiveConversation {
 | 
				
			||||||
		req.Count = defaultGetActiveConversation
 | 
							req.Count = defaultGetActiveConversation
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	opUserID := mcontext.GetOpUserID(ctx)
 | 
						req.OwnerUserID = mcontext.GetOpUserID(ctx)
 | 
				
			||||||
	conversationIDs, err := field(ctx, x.conv.GetConversationIDs,
 | 
						conversationIDs, err := field(ctx, x.conv.GetConversationIDs,
 | 
				
			||||||
		&conversation.GetConversationIDsReq{UserID: opUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs)
 | 
							&conversation.GetConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(conversationIDs) == 0 {
 | 
						if len(conversationIDs) == 0 {
 | 
				
			||||||
		return &ConversationsResp{}, nil
 | 
							return &jssdk.GetActiveConversationsResp{}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	readSeq, err := field(ctx, x.msg.GetHasReadSeqs,
 | 
						readSeq, err := field(ctx, x.msg.GetHasReadSeqs,
 | 
				
			||||||
		&msg.GetHasReadSeqsReq{UserID: opUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
 | 
							&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -64,24 +120,24 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(activeConversation) == 0 {
 | 
						if len(activeConversation) == 0 {
 | 
				
			||||||
		return &ConversationsResp{}, nil
 | 
							return &jssdk.GetActiveConversationsResp{}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sortConversations := sortActiveConversations{
 | 
						sortConversations := sortActiveConversations{
 | 
				
			||||||
		Conversation: activeConversation,
 | 
							Conversation: activeConversation,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(activeConversation) > 1 {
 | 
						if len(activeConversation) > 1 {
 | 
				
			||||||
		pinnedConversationIDs, err := field(ctx, x.conv.GetPinnedConversationIDs,
 | 
							pinnedConversationIDs, err := field(ctx, x.conv.GetPinnedConversationIDs,
 | 
				
			||||||
			&conversation.GetPinnedConversationIDsReq{UserID: opUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
 | 
								&conversation.GetPinnedConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs)
 | 
							sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sort.Sort(&sortConversations)
 | 
						sort.Sort(&sortConversations)
 | 
				
			||||||
	sortList := sortConversations.Top(req.Count)
 | 
						sortList := sortConversations.Top(int(req.Count))
 | 
				
			||||||
	conversations, err := field(ctx, x.conv.GetConversations,
 | 
						conversations, err := field(ctx, x.conv.GetConversations,
 | 
				
			||||||
		&conversation.GetConversationsReq{
 | 
							&conversation.GetConversationsReq{
 | 
				
			||||||
			OwnerUserID: opUserID,
 | 
								OwnerUserID: req.OwnerUserID,
 | 
				
			||||||
			ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
 | 
								ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
 | 
				
			||||||
				return c.ConversationID
 | 
									return c.ConversationID
 | 
				
			||||||
			})}, (*conversation.GetConversationsResp).GetConversations)
 | 
								})}, (*conversation.GetConversationsResp).GetConversations)
 | 
				
			||||||
@ -90,7 +146,7 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	msgs, err := field(ctx, x.msg.GetSeqMessage,
 | 
						msgs, err := field(ctx, x.msg.GetSeqMessage,
 | 
				
			||||||
		&msg.GetSeqMessageReq{
 | 
							&msg.GetSeqMessageReq{
 | 
				
			||||||
			UserID: opUserID,
 | 
								UserID: req.OwnerUserID,
 | 
				
			||||||
			Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
 | 
								Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
 | 
				
			||||||
				return &msg.ConversationSeqs{
 | 
									return &msg.ConversationSeqs{
 | 
				
			||||||
					ConversationID: c.ConversationID,
 | 
										ConversationID: c.ConversationID,
 | 
				
			||||||
@ -104,7 +160,7 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
 | 
				
			|||||||
	conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string {
 | 
						conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string {
 | 
				
			||||||
		return c.ConversationID
 | 
							return c.ConversationID
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	resp := make([]ConversationMsg, 0, len(sortList))
 | 
						resp := make([]*jssdk.ConversationMsg, 0, len(sortList))
 | 
				
			||||||
	for _, c := range sortList {
 | 
						for _, c := range sortList {
 | 
				
			||||||
		conv, ok := conversationMap[c.ConversationID]
 | 
							conv, ok := conversationMap[c.ConversationID]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
@ -114,13 +170,16 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
 | 
				
			|||||||
		if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
 | 
							if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
 | 
				
			||||||
			lastMsg = msgList.Msgs[0]
 | 
								lastMsg = msgList.Msgs[0]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		resp = append(resp, ConversationMsg{
 | 
							resp = append(resp, &jssdk.ConversationMsg{
 | 
				
			||||||
			Conversation: conv,
 | 
								Conversation: conv,
 | 
				
			||||||
			LastMsg:      lastMsg,
 | 
								LastMsg:      lastMsg,
 | 
				
			||||||
			MaxSeq:       c.MaxSeq,
 | 
								MaxSeq:       c.MaxSeq,
 | 
				
			||||||
			ReadSeq:      readSeq[c.ConversationID],
 | 
								ReadSeq:      readSeq[c.ConversationID],
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := x.fillConversations(ctx, resp); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	var unreadCount int64
 | 
						var unreadCount int64
 | 
				
			||||||
	for _, c := range activeConversation {
 | 
						for _, c := range activeConversation {
 | 
				
			||||||
		count := c.MaxSeq - readSeq[c.ConversationID]
 | 
							count := c.MaxSeq - readSeq[c.ConversationID]
 | 
				
			||||||
@ -128,24 +187,20 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
 | 
				
			|||||||
			unreadCount += count
 | 
								unreadCount += count
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &ConversationsResp{
 | 
						return &jssdk.GetActiveConversationsResp{
 | 
				
			||||||
		Conversations: resp,
 | 
							Conversations: resp,
 | 
				
			||||||
		UnreadCount:   unreadCount,
 | 
							UnreadCount:   unreadCount,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
 | 
					func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) {
 | 
				
			||||||
	req, err := a2r.ParseRequest[conversation.GetConversationsReq](ctx)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	req.OwnerUserID = mcontext.GetOpUserID(ctx)
 | 
						req.OwnerUserID = mcontext.GetOpUserID(ctx)
 | 
				
			||||||
	conversations, err := field(ctx, x.conv.GetConversations, req, (*conversation.GetConversationsResp).GetConversations)
 | 
						conversations, err := field(ctx, x.conv.GetConversations, &conversation.GetConversationsReq{OwnerUserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*conversation.GetConversationsResp).GetConversations)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(conversations) == 0 {
 | 
						if len(conversations) == 0 {
 | 
				
			||||||
		return &ConversationsResp{}, nil
 | 
							return &jssdk.GetConversationsResp{}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
 | 
						req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
 | 
				
			||||||
		return c.ConversationID
 | 
							return c.ConversationID
 | 
				
			||||||
@ -177,19 +232,22 @@ func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp := make([]ConversationMsg, 0, len(conversations))
 | 
						resp := make([]*jssdk.ConversationMsg, 0, len(conversations))
 | 
				
			||||||
	for _, c := range conversations {
 | 
						for _, c := range conversations {
 | 
				
			||||||
		var lastMsg *sdkws.MsgData
 | 
							var lastMsg *sdkws.MsgData
 | 
				
			||||||
		if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
 | 
							if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
 | 
				
			||||||
			lastMsg = msgList.Msgs[0]
 | 
								lastMsg = msgList.Msgs[0]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		resp = append(resp, ConversationMsg{
 | 
							resp = append(resp, &jssdk.ConversationMsg{
 | 
				
			||||||
			Conversation: c,
 | 
								Conversation: c,
 | 
				
			||||||
			LastMsg:      lastMsg,
 | 
								LastMsg:      lastMsg,
 | 
				
			||||||
			MaxSeq:       maxSeqs[c.ConversationID],
 | 
								MaxSeq:       maxSeqs[c.ConversationID],
 | 
				
			||||||
			ReadSeq:      readSeqs[c.ConversationID],
 | 
								ReadSeq:      readSeqs[c.ConversationID],
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := x.fillConversations(ctx, resp); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	var unreadCount int64
 | 
						var unreadCount int64
 | 
				
			||||||
	for conversationID, maxSeq := range maxSeqs {
 | 
						for conversationID, maxSeq := range maxSeqs {
 | 
				
			||||||
		count := maxSeq - readSeqs[conversationID]
 | 
							count := maxSeq - readSeqs[conversationID]
 | 
				
			||||||
@ -197,7 +255,7 @@ func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
 | 
				
			|||||||
			unreadCount += count
 | 
								unreadCount += count
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &ConversationsResp{
 | 
						return &jssdk.GetConversationsResp{
 | 
				
			||||||
		Conversations: resp,
 | 
							Conversations: resp,
 | 
				
			||||||
		UnreadCount:   unreadCount,
 | 
							UnreadCount:   unreadCount,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +0,0 @@
 | 
				
			|||||||
package jssdk
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/openimsdk/protocol/conversation"
 | 
					 | 
				
			||||||
	"github.com/openimsdk/protocol/sdkws"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ActiveConversationsReq struct {
 | 
					 | 
				
			||||||
	Count int `json:"count"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ConversationMsg struct {
 | 
					 | 
				
			||||||
	Conversation *conversation.Conversation `json:"conversation"`
 | 
					 | 
				
			||||||
	LastMsg      *sdkws.MsgData             `json:"lastMsg"`
 | 
					 | 
				
			||||||
	MaxSeq       int64                      `json:"maxSeq"`
 | 
					 | 
				
			||||||
	ReadSeq      int64                      `json:"readSeq"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ConversationsResp struct {
 | 
					 | 
				
			||||||
	UnreadCount   int64             `json:"unreadCount"`
 | 
					 | 
				
			||||||
	Conversations []ConversationMsg `json:"conversations"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -3,8 +3,14 @@ package jssdk
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
 | 
						"github.com/openimsdk/tools/a2r"
 | 
				
			||||||
	"github.com/openimsdk/tools/apiresp"
 | 
						"github.com/openimsdk/tools/apiresp"
 | 
				
			||||||
 | 
						"github.com/openimsdk/tools/checker"
 | 
				
			||||||
 | 
						"github.com/openimsdk/tools/errs"
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
 | 
						"google.golang.org/protobuf/proto"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
 | 
					func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A, opts ...grpc.CallOption) (*B, error), req *A, get func(*B) C) (C, error) {
 | 
				
			||||||
@ -16,11 +22,56 @@ func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A
 | 
				
			|||||||
	return get(resp), nil
 | 
						return get(resp), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func call[R any](c *gin.Context, fn func(ctx *gin.Context) (R, error)) {
 | 
					func call[A, B any](c *gin.Context, fn func(ctx context.Context, req *A) (*B, error)) {
 | 
				
			||||||
	resp, err := fn(c)
 | 
						var isJSON bool
 | 
				
			||||||
 | 
						switch contentType := c.GetHeader("Content-Type"); {
 | 
				
			||||||
 | 
						case contentType == "":
 | 
				
			||||||
 | 
							isJSON = true
 | 
				
			||||||
 | 
						case strings.Contains(contentType, "application/json"):
 | 
				
			||||||
 | 
							isJSON = true
 | 
				
			||||||
 | 
						case strings.Contains(contentType, "application/protobuf"):
 | 
				
			||||||
 | 
						case strings.Contains(contentType, "application/x-protobuf"):
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							apiresp.GinError(c, errs.ErrArgs.WrapMsg("unsupported content type"))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var req *A
 | 
				
			||||||
 | 
						if isJSON {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							req, err = a2r.ParseRequest[A](c)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								apiresp.GinError(c, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							body, err := io.ReadAll(c.Request.Body)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								apiresp.GinError(c, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							req = new(A)
 | 
				
			||||||
 | 
							if err := proto.Unmarshal(body, any(req).(proto.Message)); err != nil {
 | 
				
			||||||
 | 
								apiresp.GinError(c, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err := checker.Validate(&req); err != nil {
 | 
				
			||||||
 | 
								apiresp.GinError(c, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						resp, err := fn(c, req)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		apiresp.GinError(c, err)
 | 
							apiresp.GinError(c, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	apiresp.GinSuccess(c, resp)
 | 
						if isJSON {
 | 
				
			||||||
 | 
							apiresp.GinSuccess(c, resp)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						body, err := proto.Marshal(any(resp).(proto.Message))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							apiresp.GinError(c, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						apiresp.GinSuccess(c, body)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,37 +0,0 @@
 | 
				
			|||||||
package api
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/openimsdk/protocol/msg"
 | 
					 | 
				
			||||||
	"sort"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestName(t *testing.T) {
 | 
					 | 
				
			||||||
	val := sortActiveConversations{
 | 
					 | 
				
			||||||
		Conversation: []*msg.ActiveConversation{
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				ConversationID: "100",
 | 
					 | 
				
			||||||
				LastTime:       100,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				ConversationID: "200",
 | 
					 | 
				
			||||||
				LastTime:       200,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				ConversationID: "300",
 | 
					 | 
				
			||||||
				LastTime:       300,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				ConversationID: "400",
 | 
					 | 
				
			||||||
				LastTime:       400,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		//PinnedConversationIDs: map[string]struct{}{
 | 
					 | 
				
			||||||
		//	"100": {},
 | 
					 | 
				
			||||||
		//	"300": {},
 | 
					 | 
				
			||||||
		//},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sort.Sort(&val)
 | 
					 | 
				
			||||||
	t.Log(val)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -77,7 +77,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En
 | 
				
			|||||||
	r.Use(prommetricsGin(), gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(authRpc))
 | 
						r.Use(prommetricsGin(), gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(authRpc))
 | 
				
			||||||
	u := NewUserApi(*userRpc)
 | 
						u := NewUserApi(*userRpc)
 | 
				
			||||||
	m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID)
 | 
						m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID)
 | 
				
			||||||
	j := jssdk.NewJSSdkApi(messageRpc.Client, conversationRpc.Client)
 | 
						j := jssdk.NewJSSdkApi(userRpc.Client, friendRpc.Client, groupRpc.Client, messageRpc.Client, conversationRpc.Client)
 | 
				
			||||||
	userRouterGroup := r.Group("/user")
 | 
						userRouterGroup := r.Group("/user")
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		userRouterGroup.POST("/user_register", u.UserRegister)
 | 
							userRouterGroup.POST("/user_register", u.UserRegister)
 | 
				
			||||||
 | 
				
			|||||||
@ -273,7 +273,14 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *relation.SetFri
 | 
				
			|||||||
	return &relation.SetFriendRemarkResp{}, nil
 | 
						return &relation.SetFriendRemarkResp{}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ok.
 | 
					func (s *friendServer) GetFriendInfo(ctx context.Context, req *relation.GetFriendInfoReq) (*relation.GetFriendInfoResp, error) {
 | 
				
			||||||
 | 
						friends, err := s.db.FindFriendsWithError(ctx, req.OwnerUserID, req.FriendUserIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &relation.GetFriendInfoResp{FriendInfos: convert.FriendOnlyDB2PbOnly(friends)}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *relation.GetDesignatedFriendsReq) (resp *relation.GetDesignatedFriendsResp, err error) {
 | 
					func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *relation.GetDesignatedFriendsReq) (resp *relation.GetDesignatedFriendsResp, err error) {
 | 
				
			||||||
	resp = &relation.GetDesignatedFriendsResp{}
 | 
						resp = &relation.GetDesignatedFriendsResp{}
 | 
				
			||||||
	if datautil.Duplicate(req.FriendUserIDs) {
 | 
						if datautil.Duplicate(req.FriendUserIDs) {
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 | 
						"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 | 
				
			||||||
 | 
						"github.com/openimsdk/protocol/relation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/openimsdk/protocol/sdkws"
 | 
						"github.com/openimsdk/protocol/sdkws"
 | 
				
			||||||
	"github.com/openimsdk/tools/utils/datautil"
 | 
						"github.com/openimsdk/tools/utils/datautil"
 | 
				
			||||||
@ -35,9 +36,7 @@ func FriendPb2DB(friend *sdkws.FriendInfo) *model.Friend {
 | 
				
			|||||||
	return dbFriend
 | 
						return dbFriend
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FriendDB2Pb(ctx context.Context, friendDB *model.Friend,
 | 
					func FriendDB2Pb(ctx context.Context, friendDB *model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (*sdkws.FriendInfo, error) {
 | 
				
			||||||
	getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
 | 
					 | 
				
			||||||
) (*sdkws.FriendInfo, error) {
 | 
					 | 
				
			||||||
	users, err := getUsers(ctx, []string{friendDB.FriendUserID})
 | 
						users, err := getUsers(ctx, []string{friendDB.FriendUserID})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@ -53,11 +52,7 @@ func FriendDB2Pb(ctx context.Context, friendDB *model.Friend,
 | 
				
			|||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FriendsDB2Pb(
 | 
					func FriendsDB2Pb(ctx context.Context, friendsDB []*model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (friendsPb []*sdkws.FriendInfo, err error) {
 | 
				
			||||||
	ctx context.Context,
 | 
					 | 
				
			||||||
	friendsDB []*model.Friend,
 | 
					 | 
				
			||||||
	getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
 | 
					 | 
				
			||||||
) (friendsPb []*sdkws.FriendInfo, err error) {
 | 
					 | 
				
			||||||
	if len(friendsDB) == 0 {
 | 
						if len(friendsDB) == 0 {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -86,7 +81,21 @@ func FriendsDB2Pb(
 | 
				
			|||||||
		friendsPb = append(friendsPb, friendPb)
 | 
							friendsPb = append(friendsPb, friendPb)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return friendsPb, nil
 | 
						return friendsPb, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FriendOnlyDB2PbOnly(friendsDB []*model.Friend) []*relation.FriendInfoOnly {
 | 
				
			||||||
 | 
						return datautil.Slice(friendsDB, func(f *model.Friend) *relation.FriendInfoOnly {
 | 
				
			||||||
 | 
							return &relation.FriendInfoOnly{
 | 
				
			||||||
 | 
								OwnerUserID:    f.OwnerUserID,
 | 
				
			||||||
 | 
								FriendUserID:   f.FriendUserID,
 | 
				
			||||||
 | 
								Remark:         f.Remark,
 | 
				
			||||||
 | 
								CreateTime:     f.CreateTime.UnixMilli(),
 | 
				
			||||||
 | 
								AddSource:      f.AddSource,
 | 
				
			||||||
 | 
								OperatorUserID: f.OperatorUserID,
 | 
				
			||||||
 | 
								Ex:             f.Ex,
 | 
				
			||||||
 | 
								IsPinned:       f.IsPinned,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func FriendRequestDB2Pb(ctx context.Context, friendRequests []*model.FriendRequest, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) {
 | 
					func FriendRequestDB2Pb(ctx context.Context, friendRequests []*model.FriendRequest, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user