diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 9f5f6540e..4d8244719 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -4,6 +4,7 @@ import ( chat "Open_IM/internal/rpc/msg" "Open_IM/pkg/common/config" "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db/model" "Open_IM/pkg/common/db/mysql" "Open_IM/pkg/common/log" "Open_IM/pkg/common/middleware" @@ -11,9 +12,7 @@ import ( "Open_IM/pkg/common/token_verify" "Open_IM/pkg/common/tools" "Open_IM/pkg/common/trace_log" - cp "Open_IM/pkg/common/utils" "Open_IM/pkg/getcdv3" - pbCache "Open_IM/pkg/proto/cache" pbFriend "Open_IM/pkg/proto/friend" sdkws "Open_IM/pkg/proto/sdk_ws" "Open_IM/pkg/utils" @@ -35,9 +34,9 @@ type friendServer struct { rpcRegisterName string etcdSchema string etcdAddr []string - friendModel *mysql.Friend - friendRequestModel *mysql.FriendRequest - blackModel *mysql.Black + friendModel *model.FriendModel + friendRequestModel *model.FriendRequestModel + blackModel *model.BlackModel } func NewFriendServer(port int) *friendServer { @@ -52,9 +51,9 @@ func NewFriendServer(port int) *friendServer { func (s *friendServer) Run() { db := mysql.ConnectToDB() - s.friendModel = mysql.NewFriend(db) - s.friendRequestModel = mysql.NewFriendRequest(db) - s.blackModel = mysql.NewBlack(db) + //s.friendModel = mysql.NewFriend(db) + //s.friendRequestModel = mysql.NewFriendRequest(db) + //s.blackModel = mysql.NewBlack(db) log.NewInfo("0", "friendServer run...") @@ -115,16 +114,8 @@ func (s *friendServer) AddBlacklist(ctx context.Context, req *pbFriend.AddBlackl if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - black := imdb.Black{OwnerUserID: req.FromUserID, BlockUserID: req.ToUserID, OperatorUserID: tools.OpUserID(ctx)} - if err := s.blackModel.Create(ctx, []*imdb.Black{&black}); err != nil { - return nil, err - } - etcdConn, err := getcdv3.GetConn(ctx, config.Config.RpcRegisterName.OpenImCacheName) - if err != nil { - return nil, err - } - _, err = pbCache.NewCacheClient(etcdConn).DelBlackIDListFromCache(ctx, &pbCache.DelBlackIDListFromCacheReq{UserID: req.FromUserID}) - if err != nil { + black := mysql.Black{OwnerUserID: req.FromUserID, BlockUserID: req.ToUserID, OperatorUserID: tools.OpUserID(ctx)} + if err := s.blackModel.Create(ctx, []*mysql.Black{&black}); err != nil { return nil, err } chat.BlackAddedNotification(req) @@ -139,19 +130,19 @@ func (s *friendServer) AddFriend(ctx context.Context, req *pbFriend.AddFriendReq if err := callbackBeforeAddFriendV1(req); err != nil { return nil, err } - userIDList, err := rocksCache.GetFriendIDListFromCache(ctx, req.ToUserID) + friends1, err := s.friendModel.FindOwnerUserID(ctx, req.ToUserID) if err != nil { return nil, err } - userIDList2, err := rocksCache.GetFriendIDListFromCache(ctx, req.FromUserID) + friends2, err := s.friendModel.FindOwnerUserID(ctx, req.FromUserID) if err != nil { return nil, err } var isSend = true - for _, v := range userIDList { - if v == req.FromUserID { - for _, v2 := range userIDList2 { - if v2 == req.ToUserID { + for _, v1 := range friends1 { + if v1.FriendUserID == req.FromUserID { + for _, v2 := range friends2 { + if v2.FriendUserID == req.ToUserID { isSend = false break } @@ -159,21 +150,19 @@ func (s *friendServer) AddFriend(ctx context.Context, req *pbFriend.AddFriendReq break } } - //Cannot add non-existent users - if isSend { if _, err := GetUserInfo(ctx, req.ToUserID); err != nil { return nil, err } - friendRequest := imdb.FriendRequest{ + friendRequest := mysql.FriendRequest{ FromUserID: req.FromUserID, ToUserID: req.ToUserID, HandleResult: 0, ReqMsg: req.ReqMsg, CreateTime: time.Now(), } - if err := s.friendRequestModel.Create(ctx, []*imdb.FriendRequest{&friendRequest}); err != nil { + if err := s.friendRequestModel.Create(ctx, []*mysql.FriendRequest{&friendRequest}); err != nil { return nil, err } chat.FriendApplicationNotification(req) @@ -183,13 +172,15 @@ func (s *friendServer) AddFriend(ctx context.Context, req *pbFriend.AddFriendReq func (s *friendServer) ImportFriend(ctx context.Context, req *pbFriend.ImportFriendReq) (*pbFriend.ImportFriendResp, error) { resp := &pbFriend.ImportFriendResp{} - if !utils.IsContain(tools.OpUserID(ctx), config.Config.Manager.AppManagerUid) { - return nil, constant.ErrNoPermission.Wrap() + if err := token_verify.CheckAdmin(ctx); err != nil { + return nil, err } if _, err := GetUserInfo(ctx, req.FromUserID); err != nil { return nil, err } - for _, userID := range req.FriendUserIDList { + + var friends []*mysql.Friend + for _, userID := range utils.RemoveDuplicateElement(req.FriendUserIDList) { if _, err := GetUserInfo(ctx, userID); err != nil { return nil, err } @@ -197,41 +188,23 @@ func (s *friendServer) ImportFriend(ctx context.Context, req *pbFriend.ImportFri if err != nil { return nil, err } - var friends []*imdb.Friend switch len(fs) { case 1: if fs[0].OwnerUserID == req.FromUserID { - friends = append(friends, &imdb.Friend{OwnerUserID: userID, FriendUserID: req.FromUserID}) + friends = append(friends, &mysql.Friend{OwnerUserID: userID, FriendUserID: req.FromUserID}) } else { - friends = append(friends, &imdb.Friend{OwnerUserID: req.FromUserID, FriendUserID: userID}) + friends = append(friends, &mysql.Friend{OwnerUserID: req.FromUserID, FriendUserID: userID}) } case 0: - friends = append(friends, &imdb.Friend{OwnerUserID: userID, FriendUserID: req.FromUserID}, &imdb.Friend{OwnerUserID: req.FromUserID, FriendUserID: userID}) + friends = append(friends, &mysql.Friend{OwnerUserID: userID, FriendUserID: req.FromUserID}, &mysql.Friend{OwnerUserID: req.FromUserID, FriendUserID: userID}) default: continue } - if err := s.friendModel.Create(ctx, friends); err != nil { - return nil, err - } - } - etcdConn, err := getcdv3.GetConn(ctx, config.Config.RpcRegisterName.OpenImCacheName) - if err != nil { - return nil, err - } - cacheClient := pbCache.NewCacheClient(etcdConn) - if _, err := cacheClient.DelFriendIDListFromCache(ctx, &pbCache.DelFriendIDListFromCacheReq{UserID: req.FromUserID}); err != nil { - return nil, err - } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.FromUserID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "userID", req.FromUserID) } - for _, userID := range req.FriendUserIDList { - if _, err = cacheClient.DelFriendIDListFromCache(ctx, &pbCache.DelFriendIDListFromCacheReq{UserID: userID}); err != nil { + if len(friends) > 0 { + if err := s.friendModel.Create(ctx, friends); err != nil { return nil, err } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, userID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "userID", userID) - } } return resp, nil } @@ -250,47 +223,23 @@ func (s *friendServer) AddFriendResponse(ctx context.Context, req *pbFriend.AddF friendRequest.HandleTime = time.Now() friendRequest.HandleMsg = req.HandleMsg friendRequest.HandlerUserID = tools.OpUserID(ctx) - err = imdb.UpdateFriendApplication(friendRequest) + err = mysql.UpdateFriendApplication(friendRequest) if err != nil { return nil, err } //Change the status of the friend request form if req.HandleResult == constant.FriendFlag { - var isInsert bool //Establish friendship after find friend relationship not exists _, err := s.friendModel.Take(ctx, req.FromUserID, req.ToUserID) if errors.Is(err, gorm.ErrRecordNotFound) { - if err := s.friendModel.Create(ctx, []*imdb.Friend{{OwnerUserID: req.FromUserID, FriendUserID: req.ToUserID, OperatorUserID: tools.OpUserID(ctx)}}); err != nil { + if err := s.friendModel.Create(ctx, []*mysql.Friend{{OwnerUserID: req.FromUserID, FriendUserID: req.ToUserID, OperatorUserID: tools.OpUserID(ctx)}}); err != nil { return nil, err } - isInsert = true + chat.FriendAddedNotification(tools.OperationID(ctx), tools.OpUserID(ctx), req.FromUserID, req.ToUserID) } else if err != nil { return nil, err } - - // cache rpc - if isInsert { - etcdConn, err := getcdv3.GetConn(ctx, config.Config.RpcRegisterName.OpenImCacheName) - if err != nil { - return nil, err - } - client := pbCache.NewCacheClient(etcdConn) - - if _, err := client.DelFriendIDListFromCache(context.Background(), &pbCache.DelFriendIDListFromCacheReq{UserID: req.ToUserID}); err != nil { - return nil, err - } - if _, err := client.DelFriendIDListFromCache(context.Background(), &pbCache.DelFriendIDListFromCacheReq{UserID: req.FromUserID}); err != nil { - return nil, err - } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.ToUserID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "userID", req.ToUserID) - } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.FromUserID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "userID", req.FromUserID) - } - chat.FriendAddedNotification(tools.OperationID(ctx), tools.OpUserID(ctx), req.FromUserID, req.ToUserID) - } } if req.HandleResult == constant.FriendResponseAgree { @@ -311,20 +260,6 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbFriend.DeleteFri if err := s.friendModel.Delete(ctx, req.FromUserID, req.ToUserID); err != nil { return nil, err } - etcdConn, err := getcdv3.GetConn(ctx, config.Config.RpcRegisterName.OpenImCacheName) - if err != nil { - return nil, err - } - _, err = pbCache.NewCacheClient(etcdConn).DelFriendIDListFromCache(context.Background(), &pbCache.DelFriendIDListFromCacheReq{UserID: req.FromUserID}) - if err != nil { - return nil, err - } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.FromUserID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "DelAllFriendsInfoFromCache", req.FromUserID) - } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.ToUserID); err != nil { - trace_log.SetCtxInfo(ctx, "DelAllFriendsInfoFromCache", err, "DelAllFriendsInfoFromCache", req.ToUserID) - } chat.FriendDeletedNotification(req) return resp, nil } @@ -334,19 +269,17 @@ func (s *friendServer) GetBlacklist(ctx context.Context, req *pbFriend.GetBlackl if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - blackIDList, err := rocksCache.GetBlackListFromCache(ctx, req.FromUserID) + blacks, err := s.blackModel.FindByOwnerUserID(ctx, req.FromUserID) if err != nil { return nil, err } - for _, userID := range blackIDList { - user, err := rocksCache.GetUserInfoFromCache(ctx, userID) - if err != nil { - trace_log.SetCtxInfo(ctx, "GetUserInfoFromCache", err, "userID", userID) - continue - } - var blackUserInfo sdkws.PublicUserInfo - utils.CopyStructFields(&blackUserInfo, user) - resp.BlackUserInfoList = append(resp.BlackUserInfoList, &blackUserInfo) + blackIDList := make([]string, 0, len(blacks)) + for _, black := range blacks { + blackIDList = append(blackIDList, black.BlockUserID) + } + resp.BlackUserInfoList, err = GetPublicUserInfoBatch(ctx, blackIDList) + if err != nil { + return nil, err } return resp, nil } @@ -359,9 +292,6 @@ func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbFriend.SetFri if err := s.friendModel.UpdateRemark(ctx, req.FromUserID, req.ToUserID, req.Remark); err != nil { return nil, err } - if err := rocksCache.DelAllFriendsInfoFromCache(ctx, req.FromUserID); err != nil { - return nil, err - } chat.FriendRemarkSetNotification(tools.OperationID(ctx), tools.OpUserID(ctx), req.FromUserID, req.ToUserID) return resp, nil } @@ -372,15 +302,7 @@ func (s *friendServer) RemoveBlacklist(ctx context.Context, req *pbFriend.Remove if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - if err := s.blackModel.Delete(ctx, []*imdb.Black{{OwnerUserID: req.FromUserID, BlockUserID: req.ToUserID}}); err != nil { - return nil, err - } - etcdConn, err := getcdv3.GetConn(ctx, config.Config.RpcRegisterName.OpenImCacheName) - if err != nil { - return nil, err - } - _, err = pbCache.NewCacheClient(etcdConn).DelBlackIDListFromCache(context.Background(), &pbCache.DelBlackIDListFromCacheReq{UserID: req.FromUserID}) - if err != nil { + if err := s.blackModel.Delete(ctx, []*mysql.Black{{OwnerUserID: req.FromUserID, BlockUserID: req.ToUserID}}); err != nil { return nil, err } chat.BlackDeletedNotification(req) @@ -392,11 +314,11 @@ func (s *friendServer) IsInBlackList(ctx context.Context, req *pbFriend.IsInBlac if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - blackIDList, err := rocksCache.GetBlackListFromCache(ctx, req.FromUserID) + exist, err := s.blackModel.IsExist(ctx, req.FromUserID, req.ToUserID) if err != nil { return nil, err } - resp.Response = utils.IsContain(req.ToUserID, blackIDList) + resp.Response = exist return resp, nil } @@ -405,11 +327,11 @@ func (s *friendServer) IsFriend(ctx context.Context, req *pbFriend.IsFriendReq) if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - friendIDList, err := rocksCache.GetFriendIDListFromCache(ctx, req.FromUserID) + exist, err := s.friendModel.IsExist(ctx, req.FromUserID, req.ToUserID) if err != nil { return nil, err } - resp.Response = utils.IsContain(req.ToUserID, friendIDList) + resp.Response = exist return resp, nil } @@ -418,15 +340,26 @@ func (s *friendServer) GetFriendList(ctx context.Context, req *pbFriend.GetFrien if err := token_verify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - friendList, err := rocksCache.GetAllFriendsInfoFromCache(ctx, req.FromUserID) + friends, err := s.friendModel.FindOwnerUserID(ctx, req.FromUserID) if err != nil { return nil, err } - var userInfoList []*sdkws.FriendInfo - for _, friendUser := range friendList { - friendUserInfo := sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} - cp.FriendDBCopyOpenIM(&friendUserInfo, friendUser) - userInfoList = append(userInfoList, &friendUserInfo) + userIDList := make([]string, 0, len(friends)) + for _, f := range friends { + userIDList = append(userIDList, f.FriendUserID) + } + users, err := GetUserInfoList(ctx, userIDList) + if err != nil { + return nil, err + } + userMap := make(map[string]*sdkws.UserInfo) + for i, user := range users { + userMap[user.UserID] = users[i] + } + for _, friendUser := range friends { + friendUserInfo := sdkws.FriendInfo{FriendUser: userMap[friendUser.FriendUserID]} + utils.CopyStructFields(&friendUserInfo, friendUser) + resp.FriendInfoList = append(resp.FriendInfoList, &friendUserInfo) } return resp, nil } @@ -439,13 +372,28 @@ func (s *friendServer) GetFriendApplyList(ctx context.Context, req *pbFriend.Get return nil, err } // Find the current user friend applications received - applyUsersInfo, err := s.friendRequestModel.FindToUserID(ctx, req.FromUserID) + friendRequests, err := s.friendRequestModel.FindToUserID(ctx, req.FromUserID) + if err != nil { + return nil, err + } + userIDList := make([]string, 0, len(friendRequests)) + for _, f := range friendRequests { + userIDList = append(userIDList, f.FromUserID) + } + users, err := GetPublicUserInfoBatch(ctx, userIDList) if err != nil { return nil, err } - for _, applyUserInfo := range applyUsersInfo { + userMap := make(map[string]*sdkws.PublicUserInfo) + for i, user := range users { + userMap[user.UserID] = users[i] + } + for _, friendRequest := range friendRequests { var userInfo sdkws.FriendRequest - cp.FriendRequestDBCopyOpenIM(&userInfo, applyUserInfo) + if u, ok := userMap[friendRequest.FromUserID]; ok { + utils.CopyStructFields(&userInfo, u) + } + utils.CopyStructFields(&userInfo, friendRequest) resp.FriendRequestList = append(resp.FriendRequestList, &userInfo) } return resp, nil @@ -458,13 +406,28 @@ func (s *friendServer) GetSelfApplyList(ctx context.Context, req *pbFriend.GetSe return nil, err } // Find the self add other userinfo - usersInfo, err := s.friendRequestModel.FindFromUserID(ctx, req.FromUserID) + friendRequests, err := s.friendRequestModel.FindFromUserID(ctx, req.FromUserID) if err != nil { return nil, err } - for _, selfApplyOtherUserInfo := range usersInfo { - var userInfo sdkws.FriendRequest // pbFriend.ApplyUserInfo - cp.FriendRequestDBCopyOpenIM(&userInfo, selfApplyOtherUserInfo) + userIDList := make([]string, 0, len(friendRequests)) + for _, f := range friendRequests { + userIDList = append(userIDList, f.ToUserID) + } + users, err := GetPublicUserInfoBatch(ctx, userIDList) + if err != nil { + return nil, err + } + userMap := make(map[string]*sdkws.PublicUserInfo) + for i, user := range users { + userMap[user.UserID] = users[i] + } + for _, friendRequest := range friendRequests { + var userInfo sdkws.FriendRequest + if u, ok := userMap[friendRequest.ToUserID]; ok { + utils.CopyStructFields(&userInfo, u) + } + utils.CopyStructFields(&userInfo, friendRequest) resp.FriendRequestList = append(resp.FriendRequestList, &userInfo) } return resp, nil diff --git a/internal/rpc/friend/other.go b/internal/rpc/friend/other.go index 3beebfada..18a41f56b 100644 --- a/internal/rpc/friend/other.go +++ b/internal/rpc/friend/other.go @@ -1,14 +1,25 @@ package friend import ( + server_api_params "Open_IM/pkg/proto/sdk_ws" "context" "errors" ) -func GetUserInfo(ctx context.Context, userID string) (interface{}, error) { +func GetUserInfo(ctx context.Context, userID string) (*server_api_params.PublicUserInfo, error) { return nil, errors.New("TODO:GetUserInfo") } -func GetUserInfoBatch(ctx context.Context, userIDs []string) (interface{}, error) { +func GetPublicUserInfoBatch(ctx context.Context, userIDs []string) ([]*server_api_params.PublicUserInfo, error) { + if len(userIDs) == 0 { + return []*server_api_params.PublicUserInfo{}, nil + } + return nil, errors.New("TODO:GetUserInfo") +} + +func GetUserInfoList(ctx context.Context, userIDs []string) ([]*server_api_params.UserInfo, error) { + if len(userIDs) == 0 { + return []*server_api_params.UserInfo{}, nil + } return nil, errors.New("TODO:GetUserInfo") } diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 04f4837b4..425d7255a 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -22,11 +22,7 @@ type GroupCache struct { } func NewGroupCache(rdb redis.UniversalClient, db mysql.GroupModelInterface, opts rockscache.Options) *GroupCache { - rcClient := &rockscache.Client{ - Options: rockscache.Options{}, - } - redisClient := NewRedisClient(rdb) - return &GroupCache{rcClient: rcClient, expireTime: GroupExpireTime, db: db, redisClient: redisClient} + return &GroupCache{rcClient: rockscache.NewClient(rdb, opts), expireTime: GroupExpireTime, db: db, redisClient: NewRedisClient(rdb)} } func (g *GroupCache) getRedisClient() *RedisClient { diff --git a/pkg/common/db/model/black.go b/pkg/common/db/model/black.go new file mode 100644 index 000000000..29ef1753e --- /dev/null +++ b/pkg/common/db/model/black.go @@ -0,0 +1,52 @@ +package model + +import ( + "Open_IM/pkg/common/db/cache" + "Open_IM/pkg/common/db/mysql" + "context" + "errors" + "gorm.io/gorm" +) + +type BlackModel struct { + db *mysql.Black + cache *cache.GroupCache +} + +func (b *BlackModel) Create(ctx context.Context, blacks []*mysql.Black) (err error) { + return b.db.Create(ctx, blacks) +} + +func (b *BlackModel) Delete(ctx context.Context, blacks []*mysql.Black) (err error) { + return b.db.Delete(ctx, blacks) +} + +func (b *BlackModel) UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]interface{}) (err error) { + return b.db.UpdateByMap(ctx, ownerUserID, blockUserID, args) +} + +func (b *BlackModel) Update(ctx context.Context, blacks []*mysql.Black) (err error) { + return b.db.Update(ctx, blacks) +} + +func (b *BlackModel) Find(ctx context.Context, blacks []*mysql.Black) (blackList []*mysql.Black, err error) { + return b.db.Find(ctx, blacks) +} + +func (b *BlackModel) Take(ctx context.Context, ownerUserID, blockUserID string) (black *mysql.Black, err error) { + return b.db.Take(ctx, ownerUserID, blockUserID) +} + +func (b *BlackModel) FindByOwnerUserID(ctx context.Context, ownerUserID string) (blackList []*mysql.Black, err error) { + return b.db.FindByOwnerUserID(ctx, ownerUserID) +} + +func (b *BlackModel) IsExist(ctx context.Context, ownerUserID, blockUserID string) (bool, error) { + if _, err := b.Take(ctx, ownerUserID, blockUserID); err == nil { + return true, nil + } else if errors.Is(err, gorm.ErrRecordNotFound) { + return false, nil + } else { + return false, err + } +} diff --git a/pkg/common/db/model/friend.go b/pkg/common/db/model/friend.go new file mode 100644 index 000000000..32c4fdb75 --- /dev/null +++ b/pkg/common/db/model/friend.go @@ -0,0 +1,60 @@ +package model + +import ( + "Open_IM/pkg/common/db/cache" + "Open_IM/pkg/common/db/mysql" + "context" + "errors" + "gorm.io/gorm" +) + +type FriendModel struct { + db *mysql.Friend + cache *cache.GroupCache +} + +func (f *FriendModel) Create(ctx context.Context, friends []*mysql.Friend) (err error) { + return f.db.Create(ctx, friends) +} + +func (f *FriendModel) Delete(ctx context.Context, ownerUserID string, friendUserIDs string) (err error) { + return f.db.Delete(ctx, ownerUserID, friendUserIDs) +} + +func (f *FriendModel) UpdateByMap(ctx context.Context, ownerUserID string, args map[string]interface{}) (err error) { + return f.db.UpdateByMap(ctx, ownerUserID, args) +} + +func (f *FriendModel) Update(ctx context.Context, friends []*mysql.Friend) (err error) { + return f.db.Update(ctx, friends) +} + +func (f *FriendModel) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) { + return f.db.UpdateRemark(ctx, ownerUserID, friendUserID, remark) +} + +func (f *FriendModel) FindOwnerUserID(ctx context.Context, ownerUserID string) (friends []*mysql.Friend, err error) { + return f.db.FindOwnerUserID(ctx, ownerUserID) +} + +func (f *FriendModel) FindFriendUserID(ctx context.Context, friendUserID string) (friends []*mysql.Friend, err error) { + return f.db.FindFriendUserID(ctx, friendUserID) +} + +func (f *FriendModel) Take(ctx context.Context, ownerUserID, friendUserID string) (friend *mysql.Friend, err error) { + return f.db.Take(ctx, ownerUserID, friendUserID) +} + +func (f *FriendModel) FindUserState(ctx context.Context, userID1, userID2 string) (friends []*mysql.Friend, err error) { + return f.db.FindUserState(ctx, userID1, userID2) +} + +func (f *FriendModel) IsExist(ctx context.Context, ownerUserID, friendUserID string) (bool, error) { + if _, err := f.Take(ctx, ownerUserID, friendUserID); err == nil { + return true, nil + } else if errors.Is(err, gorm.ErrRecordNotFound) { + return false, nil + } else { + return false, err + } +} diff --git a/pkg/common/db/model/friend_request.go b/pkg/common/db/model/friend_request.go new file mode 100644 index 000000000..55e5422c0 --- /dev/null +++ b/pkg/common/db/model/friend_request.go @@ -0,0 +1,44 @@ +package model + +import ( + "Open_IM/pkg/common/db/cache" + "Open_IM/pkg/common/db/mysql" + "context" +) + +type FriendRequestModel struct { + db *mysql.FriendRequest + cache *cache.GroupCache +} + +func (f *FriendRequestModel) Create(ctx context.Context, friends []*mysql.FriendRequest) (err error) { + return f.db.Create(ctx, friends) +} + +func (f *FriendRequestModel) Delete(ctx context.Context, fromUserID, toUserID string) (err error) { + return f.db.Delete(ctx, fromUserID, toUserID) +} + +func (f *FriendRequestModel) UpdateByMap(ctx context.Context, ownerUserID string, args map[string]interface{}) (err error) { + return f.db.UpdateByMap(ctx, ownerUserID, args) +} + +func (f *FriendRequestModel) Update(ctx context.Context, friends []*mysql.FriendRequest) (err error) { + return f.db.Update(ctx, friends) +} + +func (f *FriendRequestModel) Find(ctx context.Context, ownerUserID string) (friends []*mysql.FriendRequest, err error) { + return f.db.Find(ctx, ownerUserID) +} + +func (f *FriendRequestModel) Take(ctx context.Context, fromUserID, toUserID string) (friend *mysql.FriendRequest, err error) { + return f.db.Take(ctx, fromUserID, toUserID) +} + +func (f *FriendRequestModel) FindToUserID(ctx context.Context, toUserID string) (friends []*mysql.FriendRequest, err error) { + return f.db.FindToUserID(ctx, toUserID) +} + +func (f *FriendRequestModel) FindFromUserID(ctx context.Context, fromUserID string) (friends []*mysql.FriendRequest, err error) { + return f.db.FindFromUserID(ctx, fromUserID) +} diff --git a/pkg/common/db/model/group.go b/pkg/common/db/model/group.go index c1c2a1d69..60f1cd88f 100644 --- a/pkg/common/db/model/group.go +++ b/pkg/common/db/model/group.go @@ -32,6 +32,8 @@ func NewGroupModel(db mysql.GroupModelInterface, rdb redis.UniversalClient, mdb DisableCacheRead: false, StrongConsistency: true, }) + sg := mdb.Database().Collection() + sg.Find() groupModel.mongo = mongoDB.NewMongoClient(mdb) return &groupModel } @@ -60,3 +62,20 @@ func (g *GroupModel) Delete(ctx context.Context, groupIDs []string) error { func (g *GroupModel) Take(ctx context.Context, groupID string) (group *mysql.Group, err error) { return g.cache.GetGroupInfoFromCache(ctx, groupID) } + +func (g *GroupModel) Update(ctx context.Context, groups []*mysql.Group) error { + err := g.db.DB.Transaction(func(tx *gorm.DB) error { + if err := g.db.Update(ctx, groups, tx); err != nil { + return err + } + var groupIDs []string + for _, group := range groups { + groupIDs = append(groupIDs, group.GroupID) + } + if err := g.cache.DelGroupsInfoFromCache(ctx, groupIDs); err != nil { + return err + } + return nil + }) + return err +} diff --git a/pkg/common/db/mongoDB/super_group.go b/pkg/common/db/mongoDB/super_group.go index a28289b80..980e39490 100644 --- a/pkg/common/db/mongoDB/super_group.go +++ b/pkg/common/db/mongoDB/super_group.go @@ -1,5 +1,11 @@ package mongoDB +import ( + "Open_IM/pkg/utils" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + type SuperGroup struct { GroupID string `bson:"group_id" json:"groupID"` MemberIDList []string `bson:"member_id_list" json:"memberIDList"` @@ -9,3 +15,167 @@ type UserToSuperGroup struct { UserID string `bson:"user_id" json:"userID"` GroupIDList []string `bson:"group_id_list" json:"groupIDList"` } + +func New + +func (d *db.DataBases) CreateSuperGroup(groupID string, initMemberIDList []string, memberNumCount int) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSuperGroup) + session, err := d.mongoClient.StartSession() + if err != nil { + return utils.Wrap(err, "start session failed") + } + defer session.EndSession(ctx) + sCtx := mongo.NewSessionContext(ctx, session) + superGroup := SuperGroup{ + GroupID: groupID, + MemberIDList: initMemberIDList, + } + _, err = c.InsertOne(sCtx, superGroup) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + var users []UserToSuperGroup + for _, v := range initMemberIDList { + users = append(users, UserToSuperGroup{ + UserID: v, + }) + } + upsert := true + opts := &options.UpdateOptions{ + Upsert: &upsert, + } + c = d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cUserToSuperGroup) + //_, err = c.UpdateMany(sCtx, bson.M{"user_id": bson.M{"$in": initMemberIDList}}, bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, opts) + //if err != nil { + // session.AbortTransaction(ctx) + // return utils.Wrap(err, "transaction failed") + //} + for _, userID := range initMemberIDList { + _, err = c.UpdateOne(sCtx, bson.M{"user_id": userID}, bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, opts) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + + } + return err +} + +func (d *db.DataBases) GetSuperGroup(groupID string) (SuperGroup, error) { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSuperGroup) + superGroup := SuperGroup{} + err := c.FindOne(ctx, bson.M{"group_id": groupID}).Decode(&superGroup) + return superGroup, err +} + +func (d *db.DataBases) AddUserToSuperGroup(groupID string, userIDList []string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSuperGroup) + session, err := d.mongoClient.StartSession() + if err != nil { + return utils.Wrap(err, "start session failed") + } + defer session.EndSession(ctx) + sCtx := mongo.NewSessionContext(ctx, session) + if err != nil { + return utils.Wrap(err, "start transaction failed") + } + _, err = c.UpdateOne(sCtx, bson.M{"group_id": groupID}, bson.M{"$addToSet": bson.M{"member_id_list": bson.M{"$each": userIDList}}}) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + c = d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cUserToSuperGroup) + var users []UserToSuperGroup + for _, v := range userIDList { + users = append(users, UserToSuperGroup{ + UserID: v, + }) + } + upsert := true + opts := &options.UpdateOptions{ + Upsert: &upsert, + } + for _, userID := range userIDList { + _, err = c.UpdateOne(sCtx, bson.M{"user_id": userID}, bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, opts) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + } + _ = session.CommitTransaction(ctx) + return err +} + +func (d *db.DataBases) RemoverUserFromSuperGroup(groupID string, userIDList []string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSuperGroup) + session, err := d.mongoClient.StartSession() + if err != nil { + return utils.Wrap(err, "start session failed") + } + defer session.EndSession(ctx) + sCtx := mongo.NewSessionContext(ctx, session) + _, err = c.UpdateOne(ctx, bson.M{"group_id": groupID}, bson.M{"$pull": bson.M{"member_id_list": bson.M{"$in": userIDList}}}) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + err = d.RemoveGroupFromUser(ctx, sCtx, groupID, userIDList) + if err != nil { + _ = session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + _ = session.CommitTransaction(ctx) + return err +} + +func (d *db.DataBases) GetSuperGroupByUserID(userID string) (UserToSuperGroup, error) { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cUserToSuperGroup) + var user UserToSuperGroup + _ = c.FindOne(ctx, bson.M{"user_id": userID}).Decode(&user) + return user, nil +} + +func (d *db.DataBases) DeleteSuperGroup(groupID string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSuperGroup) + session, err := d.mongoClient.StartSession() + if err != nil { + return utils.Wrap(err, "start session failed") + } + defer session.EndSession(ctx) + sCtx := mongo.NewSessionContext(ctx, session) + superGroup := &SuperGroup{} + result := c.FindOneAndDelete(sCtx, bson.M{"group_id": groupID}) + err = result.Decode(superGroup) + if err != nil { + session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + if err = d.RemoveGroupFromUser(ctx, sCtx, groupID, superGroup.MemberIDList); err != nil { + session.AbortTransaction(ctx) + return utils.Wrap(err, "transaction failed") + } + session.CommitTransaction(ctx) + return nil +} + +func (d *db.DataBases) RemoveGroupFromUser(ctx, sCtx context.Context, groupID string, userIDList []string) error { + var users []UserToSuperGroup + for _, v := range userIDList { + users = append(users, UserToSuperGroup{ + UserID: v, + }) + } + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cUserToSuperGroup) + _, err := c.UpdateOne(sCtx, bson.M{"user_id": bson.M{"$in": userIDList}}, bson.M{"$pull": bson.M{"group_id_list": groupID}}) + if err != nil { + return utils.Wrap(err, "UpdateOne transaction failed") + } + return err +} \ No newline at end of file diff --git a/pkg/common/db/mysql/user_black_list_model.go b/pkg/common/db/mysql/black.go similarity index 89% rename from pkg/common/db/mysql/user_black_list_model.go rename to pkg/common/db/mysql/black.go index bb3194645..a7e712767 100644 --- a/pkg/common/db/mysql/user_black_list_model.go +++ b/pkg/common/db/mysql/black.go @@ -52,7 +52,7 @@ func (b *Black) Update(ctx context.Context, blacks []*Black) (err error) { return utils.Wrap(b.DB.Updates(&blacks).Error, "") } -func (b *Black) Find(ctx context.Context, blacks []Black) (blackList []*Black, err error) { +func (b *Black) Find(ctx context.Context, blacks []*Black) (blackList []*Black, err error) { defer func() { trace_log.SetCtxDebug(ctx, utils.GetFuncName(1), err, "blacks", blacks, "blackList", blackList) }() @@ -63,12 +63,12 @@ func (b *Black) Find(ctx context.Context, blacks []Black) (blackList []*Black, e return blackList, utils.Wrap(GroupMemberDB.Where("(owner_user_id, block_user_id) in ?", where).Find(&blackList).Error, "") } -func (b *Black) Take(ctx context.Context, blackID string) (black *Black, err error) { +func (b *Black) Take(ctx context.Context, ownerUserID, blockUserID string) (black *Black, err error) { black = &Black{} defer func() { - trace_log.SetCtxDebug(ctx, utils.GetFuncName(1), err, "blackID", blackID, "black", *black) + trace_log.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "blockUserID", blockUserID, "black", *black) }() - return black, utils.Wrap(b.DB.Where("black_id = ?", blackID).Take(black).Error, "") + return black, utils.Wrap(b.DB.Where("owner_user_id = ? and block_user_id = ?", ownerUserID, blockUserID).Take(black).Error, "") } func (b *Black) FindByOwnerUserID(ctx context.Context, ownerUserID string) (blackList []*Black, err error) { diff --git a/pkg/common/db/mysql/friend_model_k.go b/pkg/common/db/mysql/friend_model_k.go index 9e56fa050..af62c3b0b 100644 --- a/pkg/common/db/mysql/friend_model_k.go +++ b/pkg/common/db/mysql/friend_model_k.go @@ -61,13 +61,20 @@ func (f *Friend) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, re return utils.Wrap(f.DB.Model(f).Where("owner_user_id = ? and friend_user_id = ?", ownerUserID, friendUserID).Update("remark", remark).Error, "") } -func (f *Friend) Find(ctx context.Context, ownerUserID string) (friends []*Friend, err error) { +func (f *Friend) FindOwnerUserID(ctx context.Context, ownerUserID string) (friends []*Friend, err error) { defer func() { trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "ownerUserID", ownerUserID, "friends", friends) }() return friends, utils.Wrap(f.DB.Where("owner_user_id = ?", ownerUserID).Find(&friends).Error, "") } +func (f *Friend) FindFriendUserID(ctx context.Context, friendUserID string) (friends []*Friend, err error) { + defer func() { + trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "friendUserID", friendUserID, "friends", friends) + }() + return friends, utils.Wrap(f.DB.Where("friend_user_id = ?", friendUserID).Find(&friends).Error, "") +} + func (f *Friend) Take(ctx context.Context, ownerUserID, friendUserID string) (friend *Friend, err error) { friend = &Friend{} defer trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "ownerUserID", ownerUserID, "friendUserID", friendUserID, "friend", friend) diff --git a/pkg/common/db/mysql/friend_request_model.go b/pkg/common/db/mysql/friend_request_model.go index 7f1257147..6db3e5f38 100644 --- a/pkg/common/db/mysql/friend_request_model.go +++ b/pkg/common/db/mysql/friend_request_model.go @@ -33,16 +33,14 @@ func (f *FriendRequest) Create(ctx context.Context, friends []*FriendRequest) (e defer func() { trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "friends", friends) }() - err = utils.Wrap(f.DB.Create(&friends).Error, "") - return err + return utils.Wrap(f.DB.Create(&friends).Error, "") } func (f *FriendRequest) Delete(ctx context.Context, fromUserID, toUserID string) (err error) { defer func() { trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "fromUserID", fromUserID, "toUserID", toUserID) }() - err = utils.Wrap(f.DB.Where("from_user_id = ? and to_user_id = ?", fromUserID, toUserID).Delete(&FriendRequest{}).Error, "") - return err + return utils.Wrap(f.DB.Where("from_user_id = ? and to_user_id = ?", fromUserID, toUserID).Delete(&FriendRequest{}).Error, "") } func (f *FriendRequest) UpdateByMap(ctx context.Context, ownerUserID string, args map[string]interface{}) (err error) { @@ -63,15 +61,13 @@ func (f *FriendRequest) Find(ctx context.Context, ownerUserID string) (friends [ defer func() { trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "ownerUserID", ownerUserID, "friends", friends) }() - err = utils.Wrap(f.DB.Where("owner_user_id = ?", ownerUserID).Find(&friends).Error, "") - return friends, err + return friends, utils.Wrap(f.DB.Where("owner_user_id = ?", ownerUserID).Find(&friends).Error, "") } func (f *FriendRequest) Take(ctx context.Context, fromUserID, toUserID string) (friend *FriendRequest, err error) { friend = &FriendRequest{} defer trace_log.SetCtxDebug(ctx, utils.GetSelfFuncName(), err, "fromUserID", fromUserID, "toUserID", toUserID, "friend", friend) - err = utils.Wrap(f.DB.Where("from_user_id = ? and to_user_id", fromUserID, toUserID).Take(friend).Error, "") - return friend, err + return friend, utils.Wrap(f.DB.Where("from_user_id = ? and to_user_id", fromUserID, toUserID).Take(friend).Error, "") } func (f *FriendRequest) FindToUserID(ctx context.Context, toUserID string) (friends []*FriendRequest, err error) { diff --git a/pkg/common/db/mysql/group_model_k.go b/pkg/common/db/mysql/group_model_k.go index def36f71d..4926024d6 100644 --- a/pkg/common/db/mysql/group_model_k.go +++ b/pkg/common/db/mysql/group_model_k.go @@ -9,12 +9,15 @@ import ( ) type GroupModelInterface interface { + //mysql Create(ctx context.Context, groups []*Group) (err error) Delete(ctx context.Context, groupIDs []string, tx ...*gorm.DB) (err error) UpdateByMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) Update(ctx context.Context, groups []*Group) (err error) Find(ctx context.Context, groupIDs []string) (groups []*Group, err error) Take(ctx context.Context, groupID string) (group *Group, err error) + + //mongo } type Group struct { @@ -65,11 +68,11 @@ func (*Group) UpdateByMap(ctx context.Context, groupID string, args map[string]i return utils.Wrap(GroupDB.Where("group_id = ?", groupID).Updates(args).Error, "") } -func (*Group) Update(ctx context.Context, groups []*Group) (err error) { +func (g *Group) Update(ctx context.Context, groups []*Group, tx ...*gorm.DB) (err error) { defer func() { trace_log.SetCtxDebug(ctx, utils.GetFuncName(1), err, "groups", groups) }() - return utils.Wrap(GroupDB.Updates(&groups).Error, "") + return utils.Wrap(getDBConn(g.DB, tx...).Updates(&groups).Error, "") } func (*Group) Find(ctx context.Context, groupIDs []string) (groups []*Group, err error) { diff --git a/pkg/common/token_verify/jwt_token.go b/pkg/common/token_verify/jwt_token.go index e5daef0e4..0b40012a8 100644 --- a/pkg/common/token_verify/jwt_token.go +++ b/pkg/common/token_verify/jwt_token.go @@ -173,6 +173,13 @@ func CheckAccessV3(ctx context.Context, OwnerUserID string) (err error) { return constant.ErrIdentity.Wrap(utils.GetSelfFuncName()) } +func CheckAdmin(ctx context.Context) error { + if utils.IsContain(tools.OpUserID(ctx), config.Config.Manager.AppManagerUid) { + return nil + } + return constant.ErrIdentity.Wrap() +} + func GetUserIDFromToken(token string, operationID string) (bool, string, string) { claims, err := ParseToken(token, operationID) if err != nil {