Skip to content

Commit

Permalink
feat: provide the interface required by js sdk (#2712)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
withchao and withchao authored Oct 14, 2024
1 parent 49c8440 commit 7f44319
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 109 deletions.
3 changes: 1 addition & 2 deletions cmd/openim-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
package main

import (
_ "net/http/pprof"

"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/tools/system/program"
_ "net/http/pprof"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.72
github.com/openimsdk/protocol v0.0.72-alpha.41
github.com/openimsdk/tools v0.0.50-alpha.16
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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/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/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A=
github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8=
github.com/openimsdk/protocol v0.0.72-alpha.41 h1:SMMoTc1iu+wtRqUqmIgqPJFejLgPeauOwoJ4VVG4iMQ=
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/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
Expand Down
122 changes: 90 additions & 32 deletions internal/api/jssdk/jssdk.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
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/tools/a2r"
"github.com/openimsdk/protocol/user"
"github.com/openimsdk/tools/mcontext"
"github.com/openimsdk/tools/utils/datautil"
"sort"
Expand All @@ -16,16 +20,22 @@ const (
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{
msg: msg,
conv: conv,
user: user,
friend: friend,
group: group,
msg: msg,
conv: conv,
}
}

type JSSdk struct {
msg msg.MsgClient
conv conversation.ConversationClient
user user.UserClient
friend relation.FriendClient
group group.GroupClient
msg msg.MsgClient
conv conversation.ConversationClient
}

func (x *JSSdk) GetActiveConversations(c *gin.Context) {
Expand All @@ -36,25 +46,71 @@ func (x *JSSdk) GetConversations(c *gin.Context) {
call(c, x.getConversations)
}

func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, error) {
req, err := a2r.ParseRequest[ActiveConversationsReq](ctx)
if err != nil {
return nil, err
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
}
opUserID := mcontext.GetOpUserID(ctx)
req.OwnerUserID = mcontext.GetOpUserID(ctx)
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 {
return nil, err
}
if len(conversationIDs) == 0 {
return &ConversationsResp{}, nil
return &jssdk.GetActiveConversationsResp{}, nil
}
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 {
return nil, err
}
Expand All @@ -64,24 +120,24 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
return nil, err
}
if len(activeConversation) == 0 {
return &ConversationsResp{}, nil
return &jssdk.GetActiveConversationsResp{}, nil
}
sortConversations := sortActiveConversations{
Conversation: activeConversation,
}
if len(activeConversation) > 1 {
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 {
return nil, err
}
sortConversations.PinnedConversationIDs = datautil.SliceSet(pinnedConversationIDs)
}
sort.Sort(&sortConversations)
sortList := sortConversations.Top(req.Count)
sortList := sortConversations.Top(int(req.Count))
conversations, err := field(ctx, x.conv.GetConversations,
&conversation.GetConversationsReq{
OwnerUserID: opUserID,
OwnerUserID: req.OwnerUserID,
ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
return c.ConversationID
})}, (*conversation.GetConversationsResp).GetConversations)
Expand All @@ -90,7 +146,7 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
}
msgs, err := field(ctx, x.msg.GetSeqMessage,
&msg.GetSeqMessageReq{
UserID: opUserID,
UserID: req.OwnerUserID,
Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
return &msg.ConversationSeqs{
ConversationID: c.ConversationID,
Expand All @@ -104,7 +160,7 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
conversationMap := datautil.SliceToMap(conversations, func(c *conversation.Conversation) string {
return c.ConversationID
})
resp := make([]ConversationMsg, 0, len(sortList))
resp := make([]*jssdk.ConversationMsg, 0, len(sortList))
for _, c := range sortList {
conv, ok := conversationMap[c.ConversationID]
if !ok {
Expand All @@ -114,38 +170,37 @@ func (x *JSSdk) getActiveConversations(ctx *gin.Context) (*ConversationsResp, er
if msgList, ok := msgs[c.ConversationID]; ok && len(msgList.Msgs) > 0 {
lastMsg = msgList.Msgs[0]
}
resp = append(resp, ConversationMsg{
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 &ConversationsResp{
return &jssdk.GetActiveConversationsResp{
Conversations: resp,
UnreadCount: unreadCount,
}, nil
}

func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
req, err := a2r.ParseRequest[conversation.GetConversationsReq](ctx)
if err != nil {
return nil, err
}
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, 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 {
return nil, err
}
if len(conversations) == 0 {
return &ConversationsResp{}, nil
return &jssdk.GetConversationsResp{}, nil
}
req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
return c.ConversationID
Expand Down Expand Up @@ -177,27 +232,30 @@ func (x *JSSdk) getConversations(ctx *gin.Context) (*ConversationsResp, error) {
return nil, err
}
}
resp := make([]ConversationMsg, 0, len(conversations))
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, ConversationMsg{
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 &ConversationsResp{
return &jssdk.GetConversationsResp{
Conversations: resp,
UnreadCount: unreadCount,
}, nil
Expand Down
22 changes: 0 additions & 22 deletions internal/api/jssdk/stu.go

This file was deleted.

57 changes: 54 additions & 3 deletions internal/api/jssdk/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ package jssdk
import (
"context"
"github.com/gin-gonic/gin"
"github.com/openimsdk/tools/a2r"
"github.com/openimsdk/tools/apiresp"
"github.com/openimsdk/tools/checker"
"github.com/openimsdk/tools/errs"
"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) {
Expand All @@ -16,11 +22,56 @@ func field[A, B, C any](ctx context.Context, fn func(ctx context.Context, req *A
return get(resp), nil
}

func call[R any](c *gin.Context, fn func(ctx *gin.Context) (R, error)) {
resp, err := fn(c)
func call[A, B any](c *gin.Context, fn func(ctx context.Context, req *A) (*B, error)) {
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 {
apiresp.GinError(c, err)
return
}
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, resp)
apiresp.GinSuccess(c, body)
}
Loading

0 comments on commit 7f44319

Please sign in to comment.