pull/1450/head
withchao 2 years ago
parent df7bfc67b6
commit 768e6bc758

@ -38,7 +38,7 @@ require github.com/google/uuid v1.3.1
require ( require (
github.com/IBM/sarama v1.41.3 github.com/IBM/sarama v1.41.3
github.com/OpenIMSDK/protocol v0.0.31 github.com/OpenIMSDK/protocol v0.0.31
github.com/OpenIMSDK/tools v0.0.17 github.com/OpenIMSDK/tools v0.0.18
github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible
github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1

@ -17,21 +17,20 @@ package msgtransfer
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"net/http"
"sync"
"github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/mw"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"log"
"net/http"
"sync"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
@ -39,20 +38,12 @@ import (
) )
type MsgTransfer struct { type MsgTransfer struct {
persistentCH *PersistentConsumerHandler // 聊天记录持久化到mysql的消费者 订阅的topic: ws2ms_chat
historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topicws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送 发消息到msg_to_mongo topic持久化 historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topicws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送 发消息到msg_to_mongo topic持久化
historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息以及处理删除通知消息删除的 订阅的topic: msg_to_mongo historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息以及处理删除通知消息删除的 订阅的topic: msg_to_mongo
// modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify // modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify
} }
func StartTransfer(prometheusPort int) error { func StartTransfer(prometheusPort int) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&relationtb.ChatLogModel{}); err != nil {
fmt.Printf("gorm: AutoMigrate ChatLogModel err: %v\n", err)
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
@ -78,21 +69,16 @@ func StartTransfer(prometheusPort int) error {
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb)
msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase())
msgMysModel := relation.NewChatLogGorm(db)
chatLogDatabase := controller.NewChatLogDatabase(msgMysModel)
msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel) msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel)
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgTransfer := NewMsgTransfer(chatLogDatabase, msgDatabase, &conversationRpcClient, &groupRpcClient) msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient)
return msgTransfer.Start(prometheusPort) return msgTransfer.Start(prometheusPort)
} }
func NewMsgTransfer(chatLogDatabase controller.ChatLogDatabase, func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer {
msgDatabase controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient,
) *MsgTransfer {
return &MsgTransfer{ return &MsgTransfer{
persistentCH: NewPersistentConsumerHandler(chatLogDatabase), historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient),
historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase), historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase),
} }
} }

@ -1,119 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package msgtransfer
import (
"context"
"github.com/OpenIMSDK/protocol/constant"
pbmsg "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
"github.com/IBM/sarama"
"google.golang.org/protobuf/proto"
)
type PersistentConsumerHandler struct {
persistentConsumerGroup *kfk.MConsumerGroup
chatLogDatabase controller.ChatLogDatabase
}
func NewPersistentConsumerHandler(database controller.ChatLogDatabase) *PersistentConsumerHandler {
return &PersistentConsumerHandler{
persistentConsumerGroup: kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
}, []string{config.Config.Kafka.LatestMsgToRedis.Topic},
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMySql),
chatLogDatabase: database,
}
}
func (pc *PersistentConsumerHandler) handleChatWs2Mysql(
ctx context.Context,
cMsg *sarama.ConsumerMessage,
msgKey string,
_ sarama.ConsumerGroupSession,
) {
msg := cMsg.Value
var tag bool
msgFromMQ := pbmsg.MsgDataToMQ{}
err := proto.Unmarshal(msg, &msgFromMQ)
if err != nil {
log.ZError(ctx, "msg_transfer Unmarshal msg err", err)
return
}
log.ZDebug(ctx, "handleChatWs2Mysql", "msg", msgFromMQ.MsgData)
// Control whether to store history messages (mysql)
isPersist := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsPersistent)
// Only process receiver data
if isPersist {
switch msgFromMQ.MsgData.SessionType {
case constant.SingleChatType, constant.NotificationChatType:
if msgKey == msgFromMQ.MsgData.RecvID {
tag = true
}
case constant.GroupChatType:
if msgKey == msgFromMQ.MsgData.SendID {
tag = true
}
case constant.SuperGroupChatType:
tag = true
}
if tag {
log.ZInfo(ctx, "msg_transfer msg persisting", "msg", string(msg))
if err = pc.chatLogDatabase.CreateChatLog(&msgFromMQ); err != nil {
log.ZError(ctx, "Message insert failed", err, "msg", msgFromMQ.String())
return
}
}
}
}
func (PersistentConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
func (PersistentConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
func (pc *PersistentConsumerHandler) ConsumeClaim(
sess sarama.ConsumerGroupSession,
claim sarama.ConsumerGroupClaim,
) error {
for msg := range claim.Messages() {
ctx := pc.persistentConsumerGroup.GetContextFromMsg(msg)
log.ZDebug(
ctx,
"kafka get info to mysql",
"msgTopic",
msg.Topic,
"msgPartition",
msg.Partition,
"msg",
string(msg.Value),
"key",
string(msg.Key),
)
if len(msg.Value) != 0 {
pc.handleChatWs2Mysql(ctx, msg, string(msg.Key), sess)
} else {
log.ZError(ctx, "msg get from kafka but is nil", nil, "key", msg.Key)
}
sess.MarkMessage(msg, "")
}
return nil
}

@ -17,8 +17,10 @@ package conversation
import ( import (
"context" "context"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo"
tx2 "github.com/openimsdk/open-im-server/v3/pkg/common/db/tx" "github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -53,11 +55,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
tx, err := tx2.NewAuto(context.Background(), mongo.GetClient()) conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
if err != nil {
return err
}
conversationDB, err := newmgo.NewConversationMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
@ -66,7 +64,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
pbconversation.RegisterConversationServer(server, &conversationServer{ pbconversation.RegisterConversationServer(server, &conversationServer{
conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient),
groupRpcClient: &groupRpcClient, groupRpcClient: &groupRpcClient,
conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx), conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())),
}) })
return nil return nil
} }

@ -27,19 +27,11 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func (s *friendServer) GetPaginationBlacks( func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationBlacksReq,
) (resp *pbfriend.GetPaginationBlacksResp, err error) {
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
var pageNumber, showNumber int32 total, blacks, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, req.Pagination)
if req.Pagination != nil {
pageNumber = req.Pagination.PageNumber
showNumber = req.Pagination.ShowNumber
}
blacks, total, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, pageNumber, showNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,10 +55,7 @@ func (s *friendServer) IsBlack(ctx context.Context, req *pbfriend.IsBlackReq) (*
return resp, nil return resp, nil
} }
func (s *friendServer) RemoveBlack( func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) (*pbfriend.RemoveBlackResp, error) {
ctx context.Context,
req *pbfriend.RemoveBlackReq,
) (*pbfriend.RemoveBlackResp, error) {
if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil {
return nil, err return nil, err
} }
@ -74,9 +63,6 @@ func (s *friendServer) RemoveBlack(
return nil, err return nil, err
} }
s.notificationSender.BlackDeletedNotification(ctx, req) s.notificationSender.BlackDeletedNotification(ctx, req)
if err := CallbackAfterRemoveBlack(ctx, req); err != nil {
return nil, err
}
return &pbfriend.RemoveBlackResp{}, nil return &pbfriend.RemoveBlackResp{}, nil
} }
@ -88,9 +74,6 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := CallbackBeforeAddBlack(ctx, req); err != nil {
return nil, err
}
black := relation.BlackModel{ black := relation.BlackModel{
OwnerUserID: req.OwnerUserID, OwnerUserID: req.OwnerUserID,
BlockUserID: req.BlackUserID, BlockUserID: req.BlackUserID,

@ -17,6 +17,8 @@ package friend
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
@ -32,12 +34,11 @@ import (
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
registry "github.com/OpenIMSDK/tools/discoveryregistry" registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
@ -65,17 +66,17 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
return err return err
} }
friendMongoDB, err := newmgo.NewFriendMongo(mongo.GetDatabase()) friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
friendRequestMongoDB, err := newmgo.NewFriendRequestMongo(mongo.GetDatabase()) friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
blackMongoDB, err := newmgo.NewBlackMongo(mongo.GetDatabase()) blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
@ -89,7 +90,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
&msgRpcClient, &msgRpcClient,
notification.WithRpcFunc(userRpcClient.GetUsersInfo), notification.WithRpcFunc(userRpcClient.GetUsersInfo),
) )
// Register Friend server with refactored MongoDB and Redis integrations // Register Friend server with refactored MongoDB and Redis integrations
pbfriend.RegisterFriendServer(server, &friendServer{ pbfriend.RegisterFriendServer(server, &friendServer{
friendDatabase: controller.NewFriendDatabase( friendDatabase: controller.NewFriendDatabase(
@ -311,15 +311,12 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
} }
// ok 获取接收到的好友申请(即别人主动申请的). // ok 获取接收到的好友申请(即别人主动申请的).
func (s *friendServer) GetPaginationFriendsApplyTo( func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyToReq,
) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friendRequests, total, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -333,16 +330,13 @@ func (s *friendServer) GetPaginationFriendsApplyTo(
} }
// ok 获取主动发出去的好友申请列表. // ok 获取主动发出去的好友申请列表.
func (s *friendServer) GetPaginationFriendsApplyFrom( func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyFromReq,
) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetPaginationFriendsApplyFromResp{} resp = &pbfriend.GetPaginationFriendsApplyFromResp{}
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friendRequests, total, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -355,10 +349,7 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(
} }
// ok. // ok.
func (s *friendServer) IsFriend( func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) {
ctx context.Context,
req *pbfriend.IsFriendReq,
) (resp *pbfriend.IsFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.IsFriendResp{} resp = &pbfriend.IsFriendResp{}
resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2)
@ -368,15 +359,12 @@ func (s *friendServer) IsFriend(
return resp, nil return resp, nil
} }
func (s *friendServer) GetPaginationFriends( func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsReq,
) (resp *pbfriend.GetPaginationFriendsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friends, total, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -389,10 +377,7 @@ func (s *friendServer) GetPaginationFriends(
return resp, nil return resp, nil
} }
func (s *friendServer) GetFriendIDs( func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) {
ctx context.Context,
req *pbfriend.GetFriendIDsReq,
) (resp *pbfriend.GetFriendIDsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err

@ -17,18 +17,19 @@ package group
import ( import (
"context" "context"
"fmt" "fmt"
pbconversation "github.com/OpenIMSDK/protocol/conversation" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo"
tx2 "github.com/openimsdk/open-im-server/v3/pkg/common/db/tx"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
"math/big" "math/big"
"math/rand" "math/rand"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" pbconversation "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
@ -53,19 +54,11 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
) )
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&relationtb.GroupModel{}, &relationtb.GroupMemberModel{}, &relationtb.GroupRequestModel{}); err != nil {
return err
}
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo()
if err != nil { if err != nil {
return err return err
@ -74,27 +67,23 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
groupDB, err := newmgo.NewGroupMongo(mongo.GetDatabase()) groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
groupMemberDB, err := newmgo.NewGroupMember(mongo.GetDatabase()) groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
groupRequestDB, err := newmgo.NewGroupRequestMgo(mongo.GetDatabase()) groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client)
tx, err := tx2.NewAuto(context.Background(), mongo.GetClient())
if err != nil {
return err
}
var gs groupServer var gs groupServer
database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx, grouphash.NewGroupHashFromGroupServer(&gs)) database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs))
gs.db = database gs.db = database
gs.User = userRpcClient gs.User = userRpcClient
gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {

@ -32,11 +32,11 @@ func genLogID() string {
} }
func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) { func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) {
var DBlogs []*relationtb.Log var DBlogs []*relationtb.LogModel
userID := ctx.Value(constant.OpUserID).(string) userID := ctx.Value(constant.OpUserID).(string)
platform := constant.PlatformID2Name[int(req.Platform)] platform := constant.PlatformID2Name[int(req.Platform)]
for _, fileURL := range req.FileURLs { for _, fileURL := range req.FileURLs {
log := relationtb.Log{ log := relationtb.LogModel{
Version: req.Version, Version: req.Version,
SystemType: req.SystemType, SystemType: req.SystemType,
Platform: platform, Platform: platform,
@ -57,7 +57,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq)
} }
} }
if log.LogID == "" { if log.LogID == "" {
return nil, errs.ErrData.Wrap("Log id gen error") return nil, errs.ErrData.Wrap("LogModel id gen error")
} }
DBlogs = append(DBlogs, &log) DBlogs = append(DBlogs, &log)
} }
@ -92,8 +92,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq)
return &third.DeleteLogsResp{}, nil return &third.DeleteLogsResp{}, nil
} }
func dbToPbLogInfos(logs []*relationtb.Log) []*third.LogInfo { func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo {
db2pbForLogInfo := func(log *relationtb.Log) *third.LogInfo { db2pbForLogInfo := func(log *relationtb.LogModel) *third.LogInfo {
return &third.LogInfo{ return &third.LogInfo{
Filename: log.FileName, Filename: log.FileName,
UserID: log.UserID, UserID: log.UserID,

@ -17,17 +17,17 @@ package third
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"net/url" "net/url"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/kodo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/protocol/third"
@ -44,11 +44,11 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
logdb, err := newmgo.NewLogMongo(mongo.GetDatabase()) logdb, err := mgo.NewLogMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
s3db, err := newmgo.NewS3Mongo(mongo.GetDatabase()) s3db, err := mgo.NewS3Mongo(mongo.GetDatabase())
if err != nil { if err != nil {
return err return err
} }
@ -77,8 +77,6 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
o, err = cos.NewCos() o, err = cos.NewCos()
case "oss": case "oss":
o, err = oss.NewOSS() o, err = oss.NewOSS()
case "kodo":
o, err = kodo.NewKodo()
default: default:
err = fmt.Errorf("invalid object enable: %s", enable) err = fmt.Errorf("invalid object enable: %s", enable)
} }

@ -17,11 +17,13 @@ package user
import ( import (
"context" "context"
"errors" "errors"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo"
tx2 "github.com/openimsdk/open-im-server/v3/pkg/common/db/tx"
"strings" "strings"
"time" "time"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
@ -70,17 +72,13 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
for k, v := range config.Config.Manager.UserID { for k, v := range config.Config.Manager.UserID {
users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin}) users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin})
} }
userDB, err := newmgo.NewUserMongo(mongo.GetDatabase()) userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
if err != nil {
return err
}
tx, err := tx2.NewAuto(context.Background(), mongo.GetClient())
if err != nil { if err != nil {
return err return err
} }
cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
database := controller.NewUserDatabase(userDB, cache, tx, userMongoDB) database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)

@ -17,11 +17,13 @@ package tools
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo"
tx2 "github.com/openimsdk/open-im-server/v3/pkg/common/db/tx"
"math" "math"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
@ -78,43 +80,40 @@ func InitMsgTool() (*MsgTool, error) {
return nil, err return nil, err
} }
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
userDB, err := newmgo.NewUserMongo(mongo.GetDatabase()) userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
if err != nil {
return nil, err
}
tx, err := tx2.NewAuto(context.Background(), mongo.GetClient())
if err != nil { if err != nil {
return nil, err return nil, err
} }
msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase( userDatabase := controller.NewUserDatabase(
userDB, userDB,
cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()),
tx, ctxTx,
userMongoDB, userMongoDB,
) )
groupDB, err := newmgo.NewGroupMongo(mongo.GetDatabase()) groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupMemberDB, err := newmgo.NewGroupMember(mongo.GetDatabase()) groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase())
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupRequestDB, err := newmgo.NewGroupRequestMgo(mongo.GetDatabase()) groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase())
if err != nil { if err != nil {
return nil, err return nil, err
} }
conversationDB, err := newmgo.NewConversationMongo(mongo.GetDatabase()) conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx, nil) groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, ctxTx, nil)
conversationDatabase := controller.NewConversationDatabase( conversationDatabase := controller.NewConversationDatabase(
conversationDB, conversationDB,
cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB),
tx, ctxTx,
) )
msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgRpcClient := rpcclient.NewMessageRpcClient(discov)
msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient))

@ -17,11 +17,12 @@ package cache
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
"strconv" "strconv"
"time" "time"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/dtm-labs/rockscache" "github.com/dtm-labs/rockscache"
@ -318,7 +319,12 @@ func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID strin
}) })
} }
func (g *GroupCacheRedis) GetGroupMembersPage(ctx context.Context, groupID string, userIDs []string, showNumber, pageNumber int32) (total uint32, groupMembers []*relationtb.GroupMemberModel, err error) { func (g *GroupCacheRedis) GetGroupMembersPage(
ctx context.Context,
groupID string,
userIDs []string,
showNumber, pageNumber int32,
) (total uint32, groupMembers []*relationtb.GroupMemberModel, err error) {
groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID) groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err

@ -173,20 +173,7 @@ func (c *msgCache) getSeqs(ctx context.Context, items []string, getkey func(s st
} }
func (c *msgCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error { func (c *msgCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error {
var retErr error return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey)
for {
select {
case <-ctx.Done():
return errs.Wrap(retErr, "SetMaxSeq redis retry too many amount")
default:
retErr = c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey)
if retErr != nil {
time.Sleep(time.Second * 2)
continue
}
return nil
}
}
} }
func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) { func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) {
@ -194,21 +181,7 @@ func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m
} }
func (c *msgCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) { func (c *msgCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) {
var retErr error return c.getSeq(ctx, conversationID, c.getMaxSeqKey)
var retData int64
for {
select {
case <-ctx.Done():
return -1, errs.Wrap(retErr, "GetMaxSeq redis retry too many amount")
default:
retData, retErr = c.getSeq(ctx, conversationID, c.getMaxSeqKey)
if retErr != nil && errs.Unwrap(retErr) != redis.Nil {
time.Sleep(time.Second * 2)
continue
}
return retData, retErr
}
}
} }
func (c *msgCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error { func (c *msgCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
@ -672,35 +645,19 @@ func (c *msgCache) PipeDeleteMessages(ctx context.Context, conversationID string
} }
func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error { func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error {
var ( vals, err := c.rdb.Keys(ctx, c.allMessageCacheKey(conversationID)).Result()
cursor uint64 if errors.Is(err, redis.Nil) {
keys []string return nil
err error }
if err != nil {
key = c.allMessageCacheKey(conversationID) return errs.Wrap(err)
) }
for _, v := range vals {
for { if err := c.rdb.Del(ctx, v).Err(); err != nil {
// scan up to 10000 at a time, the count (10000) param refers to the number of scans on redis server.
// if the count is too small, needs to be run scan on redis frequently.
var limit int64 = 10000
keys, cursor, err = c.rdb.Scan(ctx, cursor, key, limit).Result()
if err != nil {
return errs.Wrap(err) return errs.Wrap(err)
} }
for _, key := range keys {
err := c.rdb.Del(ctx, key).Err()
if err != nil {
return errs.Wrap(err)
}
}
// scan end
if cursor == 0 {
return nil
}
} }
return nil
} }
func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []int64) error { func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []int64) error {

@ -385,50 +385,3 @@ func testParallelDeleteMessagesMix(t *testing.T, cid string, seqs []int64, input
assert.EqualValues(t, 1, val) // exists assert.EqualValues(t, 1, val) // exists
} }
} }
func TestCleanUpOneConversationAllMsg(t *testing.T) {
rdb := redis.NewClient(&redis.Options{})
defer rdb.Close()
cacher := msgCache{rdb: rdb}
count := 1000
prefix := fmt.Sprintf("%v", rand.Int63())
ids := []string{}
for i := 0; i < count; i++ {
id := fmt.Sprintf("%v-cid-%v", prefix, rand.Int63())
ids = append(ids, id)
key := cacher.allMessageCacheKey(id)
rdb.Set(context.Background(), key, "openim", 0)
}
// delete 100 keys with scan.
for i := 0; i < 100; i++ {
pickedKey := ids[i]
err := cacher.CleanUpOneConversationAllMsg(context.Background(), pickedKey)
assert.Nil(t, err)
ls, err := rdb.Keys(context.Background(), pickedKey).Result()
assert.Nil(t, err)
assert.Equal(t, 0, len(ls))
rcode, err := rdb.Exists(context.Background(), pickedKey).Result()
assert.Nil(t, err)
assert.EqualValues(t, 0, rcode) // non-exists
}
sid := fmt.Sprintf("%v-cid-*", prefix)
ls, err := rdb.Keys(context.Background(), cacher.allMessageCacheKey(sid)).Result()
assert.Nil(t, err)
assert.Equal(t, count-100, len(ls))
// delete fuzzy matching keys.
err = cacher.CleanUpOneConversationAllMsg(context.Background(), sid)
assert.Nil(t, err)
// don't contains keys matched `{prefix}-cid-{random}` on redis
ls, err = rdb.Keys(context.Background(), cacher.allMessageCacheKey(sid)).Result()
assert.Nil(t, err)
assert.Equal(t, 0, len(ls))
}

@ -18,11 +18,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"hash/crc32" "hash/crc32"
"strconv" "strconv"
"time" "time"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"

@ -17,6 +17,8 @@ package controller
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@ -30,12 +32,7 @@ type BlackDatabase interface {
// Delete 删除黑名单 // Delete 删除黑名单
Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error)
// FindOwnerBlacks 获取黑名单列表 // FindOwnerBlacks 获取黑名单列表
FindOwnerBlacks( FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error)
ctx context.Context,
ownerUserID string,
pageNumber, showNumber int32,
) (blacks []*relation.BlackModel, total int64, err error)
FindBlackIDs(ctx context.Context, ownerUserID string) (blackIDs []string, err error)
FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) FindBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error)
// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true) // CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true)
CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error)
@ -75,12 +72,8 @@ func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relat
} }
// FindOwnerBlacks 获取黑名单列表. // FindOwnerBlacks 获取黑名单列表.
func (b *blackDatabase) FindOwnerBlacks( func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) {
ctx context.Context, return b.black.FindOwnerBlacks(ctx, ownerUserID, pagination)
ownerUserID string,
pageNumber, showNumber int32,
) (blacks []*relation.BlackModel, total int64, err error) {
return b.black.FindOwnerBlacks(ctx, ownerUserID, pageNumber, showNumber)
} }
// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true). // CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true).

@ -1,37 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controller
import (
pbmsg "github.com/OpenIMSDK/protocol/msg"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
type ChatLogDatabase interface {
CreateChatLog(msg *pbmsg.MsgDataToMQ) error
}
func NewChatLogDatabase(chatLogModelInterface relationtb.ChatLogModelInterface) ChatLogDatabase {
return &chatLogDatabase{chatLogModel: chatLogModelInterface}
}
type chatLogDatabase struct {
chatLogModel relationtb.ChatLogModelInterface
}
func (c *chatLogDatabase) CreateChatLog(msg *pbmsg.MsgDataToMQ) error {
return c.chatLogModel.Create(msg)
}

@ -16,9 +16,10 @@ package controller
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
@ -237,7 +238,9 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs
if err != nil { if err != nil {
return err return err
} }
cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID).DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...) cache = cache.DelConversationIDs(ownerUserID).
DelUserConversationIDsHash(ownerUserID).
DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...)
} }
return cache.ExecDel(ctx) return cache.ExecDel(ctx)
}) })

@ -18,7 +18,7 @@ import (
"context" "context"
"time" "time"
"gorm.io/gorm" "github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
@ -47,35 +47,15 @@ type FriendDatabase interface {
// 更新好友备注 // 更新好友备注
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
// 获取ownerUserID的好友列表 // 获取ownerUserID的好友列表
PageOwnerFriends( PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error)
ctx context.Context,
ownerUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error)
// friendUserID在哪些人的好友列表中 // friendUserID在哪些人的好友列表中
PageInWhoseFriends( PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error)
ctx context.Context,
friendUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error)
// 获取我发出去的好友申请 // 获取我发出去的好友申请
PageFriendRequestFromMe( PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error)
ctx context.Context,
userID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendRequestModel, total int64, err error)
// 获取我收到的的好友申请 // 获取我收到的的好友申请
PageFriendRequestToMe( PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error)
ctx context.Context,
userID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendRequestModel, total int64, err error)
// 获取某人指定好友的信息 // 获取某人指定好友的信息
FindFriendsWithError( FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error)
ctx context.Context,
ownerUserID string,
friendUserIDs []string,
) (friends []*relation.FriendModel, err error)
FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error)
} }
@ -83,24 +63,16 @@ type FriendDatabase interface {
type friendDatabase struct { type friendDatabase struct {
friend relation.FriendModelInterface friend relation.FriendModelInterface
friendRequest relation.FriendRequestModelInterface friendRequest relation.FriendRequestModelInterface
tx tx.Tx tx tx.CtxTx
cache cache.FriendCache cache cache.FriendCache
} }
func NewFriendDatabase( func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.CtxTx) FriendDatabase {
friend relation.FriendModelInterface,
friendRequest relation.FriendRequestModelInterface,
cache cache.FriendCache,
tx tx.Tx,
) FriendDatabase {
return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx} return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx}
} }
// ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true). // ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true).
func (f *friendDatabase) CheckIn( func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) {
ctx context.Context,
userID1, userID2 string,
) (inUser1Friends bool, inUser2Friends bool, err error) {
userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1) userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1)
if err != nil { if err != nil {
return return
@ -113,50 +85,35 @@ func (f *friendDatabase) CheckIn(
} }
// 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增. // 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增.
func (f *friendDatabase) AddFriendRequest( func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) {
ctx context.Context, return f.tx.Transaction(ctx, func(ctx context.Context) error {
fromUserID, toUserID string, _, err := f.friendRequest.Take(ctx, fromUserID, toUserID)
reqMsg string, switch {
ex string, case err == nil:
) (err error) {
return f.tx.Transaction(func(tx any) error {
_, err := f.friendRequest.NewTx(tx).Take(ctx, fromUserID, toUserID)
// 有db错误
if err != nil && errs.Unwrap(err) != gorm.ErrRecordNotFound {
return err
}
// 无错误 则更新
if err == nil {
m := make(map[string]any, 1) m := make(map[string]any, 1)
m["handle_result"] = 0 m["handle_result"] = 0
m["handle_msg"] = "" m["handle_msg"] = ""
m["req_msg"] = reqMsg m["req_msg"] = reqMsg
m["ex"] = ex m["ex"] = ex
m["create_time"] = time.Now() m["create_time"] = time.Now()
if err := f.friendRequest.NewTx(tx).UpdateByMap(ctx, fromUserID, toUserID, m); err != nil { return f.friendRequest.UpdateByMap(ctx, fromUserID, toUserID, m)
return err case relation.IsNotFound(err):
} return f.friendRequest.Create(
return nil ctx,
} []*relation.FriendRequestModel{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}},
// gorm.ErrRecordNotFound 错误,则新增 )
if err := f.friendRequest.NewTx(tx).Create(ctx, []*relation.FriendRequestModel{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}}); err != nil { default:
return err return err
} }
return nil
}) })
} }
// (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可. // (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可.
func (f *friendDatabase) BecomeFriends( func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) {
ctx context.Context, return f.tx.Transaction(ctx, func(ctx context.Context) error {
ownerUserID string, cache := f.cache.NewCache()
friendUserIDs []string,
addSource int32,
) (err error) {
cache := f.cache.NewCache()
if err := f.tx.Transaction(func(tx any) error {
// 先find 找出重复的 去掉重复的 // 先find 找出重复的 去掉重复的
fs1, err := f.friend.NewTx(tx).FindFriends(ctx, ownerUserID, friendUserIDs) fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil { if err != nil {
return err return err
} }
@ -168,11 +125,11 @@ func (f *friendDatabase) BecomeFriends(
return e.FriendUserID return e.FriendUserID
}) })
err = f.friend.NewTx(tx).Create(ctx, fs11) err = f.friend.Create(ctx, fs11)
if err != nil { if err != nil {
return err return err
} }
fs2, err := f.friend.NewTx(tx).FindReversalFriends(ctx, ownerUserID, friendUserIDs) fs2, err := f.friend.FindReversalFriends(ctx, ownerUserID, friendUserIDs)
if err != nil { if err != nil {
return err return err
} }
@ -184,24 +141,19 @@ func (f *friendDatabase) BecomeFriends(
fs22 := utils.DistinctAny(fs2, func(e *relation.FriendModel) string { fs22 := utils.DistinctAny(fs2, func(e *relation.FriendModel) string {
return e.OwnerUserID return e.OwnerUserID
}) })
err = f.friend.NewTx(tx).Create(ctx, fs22) err = f.friend.Create(ctx, fs22)
if err != nil { if err != nil {
return err return err
} }
newFriendIDs = append(newFriendIDs, ownerUserID) newFriendIDs = append(newFriendIDs, ownerUserID)
cache = cache.DelFriendIDs(newFriendIDs...) cache = cache.DelFriendIDs(newFriendIDs...)
return nil return cache.ExecDel(ctx)
}); err != nil {
return nil })
}
return cache.ExecDel(ctx)
} }
// 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝. // 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝.
func (f *friendDatabase) RefuseFriendRequest( func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
ctx context.Context,
friendRequest *relation.FriendRequestModel,
) (err error) {
fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil { if err != nil {
return err return err
@ -220,14 +172,11 @@ func (f *friendDatabase) RefuseFriendRequest(
} }
// AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略). // AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略).
func (f *friendDatabase) AgreeFriendRequest( func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
ctx context.Context, return f.tx.Transaction(ctx, func(ctx context.Context) error {
friendRequest *relation.FriendRequestModel,
) (err error) {
return f.tx.Transaction(func(tx any) error {
defer log.ZDebug(ctx, "return line") defer log.ZDebug(ctx, "return line")
now := time.Now() now := time.Now()
fr, err := f.friendRequest.NewTx(tx).Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil { if err != nil {
return err return err
} }
@ -237,25 +186,25 @@ func (f *friendDatabase) AgreeFriendRequest(
friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx) friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx)
friendRequest.HandleResult = constant.FriendResponseAgree friendRequest.HandleResult = constant.FriendResponseAgree
friendRequest.HandleTime = now friendRequest.HandleTime = now
err = f.friendRequest.NewTx(tx).Update(ctx, friendRequest) err = f.friendRequest.Update(ctx, friendRequest)
if err != nil { if err != nil {
return err return err
} }
fr2, err := f.friendRequest.NewTx(tx).Take(ctx, friendRequest.ToUserID, friendRequest.FromUserID) fr2, err := f.friendRequest.Take(ctx, friendRequest.ToUserID, friendRequest.FromUserID)
if err == nil && fr2.HandleResult == constant.FriendResponseNotHandle { if err == nil && fr2.HandleResult == constant.FriendResponseNotHandle {
fr2.HandlerUserID = mcontext.GetOpUserID(ctx) fr2.HandlerUserID = mcontext.GetOpUserID(ctx)
fr2.HandleResult = constant.FriendResponseAgree fr2.HandleResult = constant.FriendResponseAgree
fr2.HandleTime = now fr2.HandleTime = now
err = f.friendRequest.NewTx(tx).Update(ctx, fr2) err = f.friendRequest.Update(ctx, fr2)
if err != nil { if err != nil {
return err return err
} }
} else if err != nil && errs.Unwrap(err) != gorm.ErrRecordNotFound { } else if err != nil && (!relation.IsNotFound(err)) {
return err return err
} }
exists, err := f.friend.NewTx(tx).FindUserState(ctx, friendRequest.FromUserID, friendRequest.ToUserID) exists, err := f.friend.FindUserState(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil { if err != nil {
return err return err
} }
@ -286,7 +235,7 @@ func (f *friendDatabase) AgreeFriendRequest(
) )
} }
if len(adds) > 0 { if len(adds) > 0 {
if err := f.friend.NewTx(tx).Create(ctx, adds); err != nil { if err := f.friend.Create(ctx, adds); err != nil {
return err return err
} }
} }
@ -311,47 +260,27 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs
} }
// 获取ownerUserID的好友列表 无结果不返回错误. // 获取ownerUserID的好友列表 无结果不返回错误.
func (f *friendDatabase) PageOwnerFriends( func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
ctx context.Context, return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination)
ownerUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error) {
return f.friend.FindOwnerFriends(ctx, ownerUserID, pageNumber, showNumber)
} }
// friendUserID在哪些人的好友列表中. // friendUserID在哪些人的好友列表中.
func (f *friendDatabase) PageInWhoseFriends( func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
ctx context.Context, return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination)
friendUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error) {
return f.friend.FindInWhoseFriends(ctx, friendUserID, pageNumber, showNumber)
} }
// 获取我发出去的好友申请 无结果不返回错误. // 获取我发出去的好友申请 无结果不返回错误.
func (f *friendDatabase) PageFriendRequestFromMe( func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
ctx context.Context, return f.friendRequest.FindFromUserID(ctx, userID, pagination)
userID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendRequestModel, total int64, err error) {
return f.friendRequest.FindFromUserID(ctx, userID, pageNumber, showNumber)
} }
// 获取我收到的的好友申请 无结果不返回错误. // 获取我收到的的好友申请 无结果不返回错误.
func (f *friendDatabase) PageFriendRequestToMe( func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
ctx context.Context, return f.friendRequest.FindToUserID(ctx, userID, pagination)
userID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendRequestModel, total int64, err error) {
return f.friendRequest.FindToUserID(ctx, userID, pageNumber, showNumber)
} }
// 获取某人指定好友的信息 如果有好友不存在,也返回错误. // 获取某人指定好友的信息 如果有好友不存在,也返回错误.
func (f *friendDatabase) FindFriendsWithError( func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) {
ctx context.Context,
ownerUserID string,
friendUserIDs []string,
) (friends []*relation.FriendModel, err error) {
friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil { if err != nil {
return return
@ -362,10 +291,7 @@ func (f *friendDatabase) FindFriendsWithError(
return return
} }
func (f *friendDatabase) FindFriendUserIDs( func (f *friendDatabase) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) {
ctx context.Context,
ownerUserID string,
) (friendUserIDs []string, err error) {
return f.cache.GetFriendIDs(ctx, ownerUserID) return f.cache.GetFriendIDs(ctx, ownerUserID)
} }

@ -16,10 +16,11 @@ package controller
import ( import (
"context" "context"
"github.com/dtm-labs/rockscache"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/dtm-labs/rockscache"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@ -74,7 +75,14 @@ type GroupDatabase interface {
DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error
} }
func NewGroupDatabase(rdb redis.UniversalClient, groupDB relationtb.GroupModelInterface, groupMemberDB relationtb.GroupMemberModelInterface, groupRequestDB relationtb.GroupRequestModelInterface, ctxTx tx.CtxTx, groupHash cache.GroupHash) GroupDatabase { func NewGroupDatabase(
rdb redis.UniversalClient,
groupDB relationtb.GroupModelInterface,
groupMemberDB relationtb.GroupMemberModelInterface,
groupRequestDB relationtb.GroupRequestModelInterface,
ctxTx tx.CtxTx,
groupHash cache.GroupHash,
) GroupDatabase {
rcOptions := rockscache.NewDefaultOptions() rcOptions := rockscache.NewDefaultOptions()
rcOptions.StrongConsistency = true rcOptions.StrongConsistency = true
rcOptions.RandomExpireAdjustment = 0.2 rcOptions.RandomExpireAdjustment = 0.2

@ -357,9 +357,7 @@ func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversa
} }
func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) { func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) {
cancelCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) currentMaxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
defer cancel()
currentMaxSeq, err := db.cache.GetMaxSeq(cancelCtx, conversationID)
if err != nil && errs.Unwrap(err) != redis.Nil { if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZError(ctx, "db.cache.GetMaxSeq", err) log.ZError(ctx, "db.cache.GetMaxSeq", err)
return 0, false, err return 0, false, err
@ -386,21 +384,19 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa
prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum)) prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum))
log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID) log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID)
} else { } else {
prommetrics.MsgInsertRedisSuccessCounter.Add(float64(len(msgs))) prommetrics.MsgInsertRedisSuccessCounter.Inc()
} }
cancelCtx, cancel = context.WithTimeout(ctx, 1*time.Minute) err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq)
defer cancel()
err = db.cache.SetMaxSeq(cancelCtx, conversationID, currentMaxSeq)
if err != nil { if err != nil {
log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID) log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID)
prommetrics.SeqSetFailedCounter.Inc() prommetrics.SeqSetFailedCounter.Inc()
} }
err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap)
if err2 != nil { if err != nil {
log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID) log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID)
prommetrics.SeqSetFailedCounter.Inc() prommetrics.SeqSetFailedCounter.Inc()
} }
return lastMaxSeq, isNew, errs.Wrap(err, "redis SetMaxSeq error") return lastMaxSeq, isNew, utils.Wrap(err, "")
} }
func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) { func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) {
@ -658,26 +654,16 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (int64, int64, []*sdkws.MsgData, error) { func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (int64, int64, []*sdkws.MsgData, error) {
userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
if err != nil { if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZError(ctx, "cache.GetConversationUserMinSeq error", err) return 0, 0, nil, err
if errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
} }
minSeq, err := db.cache.GetMinSeq(ctx, conversationID) minSeq, err := db.cache.GetMinSeq(ctx, conversationID)
if err != nil { if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZError(ctx, "cache.GetMinSeq error", err) return 0, 0, nil, err
if errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
} }
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
if err != nil { if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZError(ctx, "cache.GetMaxSeq error", err) return 0, 0, nil, err
if errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
} }
if userMinSeq < minSeq { if userMinSeq < minSeq {
minSeq = userMinSeq minSeq = userMinSeq
@ -690,16 +676,34 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co
} }
successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs) successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs)
if err != nil { if err != nil {
log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID) if err != redis.Nil {
log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID)
}
} }
log.ZInfo(ctx, "db.cache.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", seqs, "successMsgs", log.ZInfo(
len(successMsgs), "failedSeqs", failedSeqs, "conversationID", conversationID) ctx,
"db.cache.GetMessagesBySeq",
"userID",
userID,
"conversationID",
conversationID,
"seqs",
seqs,
"successMsgs",
len(successMsgs),
"failedSeqs",
failedSeqs,
"conversationID",
conversationID,
)
if len(failedSeqs) > 0 { if len(failedSeqs) > 0 {
mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs) mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs)
if err != nil { if err != nil {
return 0, 0, nil, err return 0, 0, nil, err
} }
successMsgs = append(successMsgs, mongoMsgs...) successMsgs = append(successMsgs, mongoMsgs...)
} }
return minSeq, maxSeq, successMsgs, nil return minSeq, maxSeq, successMsgs, nil

@ -16,9 +16,10 @@ package controller
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
@ -27,10 +28,10 @@ type ThirdDatabase interface {
FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error
SetAppBadge(ctx context.Context, userID string, value int) error SetAppBadge(ctx context.Context, userID string, value int) error
// about log for debug // about log for debug
UploadLogs(ctx context.Context, logs []*relation.Log) error UploadLogs(ctx context.Context, logs []*relation.LogModel) error
DeleteLogs(ctx context.Context, logID []string, userID string) error DeleteLogs(ctx context.Context, logID []string, userID string) error
SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.Log, error) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error)
GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.Log, error) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error)
} }
type thirdDatabase struct { type thirdDatabase struct {
@ -44,17 +45,17 @@ func (t *thirdDatabase) DeleteLogs(ctx context.Context, logID []string, userID s
} }
// GetLogs implements ThirdDatabase. // GetLogs implements ThirdDatabase.
func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.Log, error) { func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error) {
return t.logdb.Get(ctx, LogIDs, userID) return t.logdb.Get(ctx, LogIDs, userID)
} }
// SearchLogs implements ThirdDatabase. // SearchLogs implements ThirdDatabase.
func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.Log, error) { func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) {
return t.logdb.Search(ctx, keyword, start, end, pagination) return t.logdb.Search(ctx, keyword, start, end, pagination)
} }
// UploadLogs implements ThirdDatabase. // UploadLogs implements ThirdDatabase.
func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.Log) error { func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.LogModel) error {
return t.logdb.Create(ctx, logs) return t.logdb.Create(ctx, logs)
} }

@ -16,10 +16,12 @@ package controller
import ( import (
"context" "context"
"time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time"
"github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/protocol/user"
@ -79,35 +81,33 @@ func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache,
return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB} return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB}
} }
func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error { func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error {
// Extract user IDs from the given user models. // Extract user IDs from the given user models.
userIDs := utils.Slice(users, func(e *relation.UserModel) string { userIDs := utils.Slice(users, func(e *relation.UserModel) string {
return e.UserID return e.UserID
}) })
// Find existing users in the database. // Find existing users in the database.
existingUsers, err := u.userDB.Find(ctx, userIDs) existingUsers, err := u.userDB.Find(ctx, userIDs)
if err != nil { if err != nil {
return err return err
} }
// Determine which users are missing from the database. // Determine which users are missing from the database.
missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string {
return e.UserID return e.UserID
}) })
// Create records for missing users. // Create records for missing users.
if len(missingUsers) > 0 { if len(missingUsers) > 0 {
if err := u.userDB.Create(ctx, missingUsers); err != nil { if err := u.userDB.Create(ctx, missingUsers); err != nil {
return err return err
} }
} }
return nil return nil
} }
// FindWithError Get the information of the specified user and return an error if the userID is not found. // FindWithError Get the information of the specified user and return an error if the userID is not found.
func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
users, err = u.cache.GetUsersInfo(ctx, userIDs) users, err = u.cache.GetUsersInfo(ctx, userIDs)

@ -0,0 +1,91 @@
package mgo
import (
"context"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewBlackMongo(db *mongo.Database) (relation.BlackModelInterface, error) {
coll := db.Collection("black")
_, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
Keys: bson.D{
{Key: "owner_user_id", Value: 1},
{Key: "block_user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &BlackMgo{coll: coll}, nil
}
type BlackMgo struct {
coll *mongo.Collection
}
func (b *BlackMgo) blackFilter(ownerUserID, blockUserID string) bson.M {
return bson.M{
"owner_user_id": ownerUserID,
"block_user_id": blockUserID,
}
}
func (b *BlackMgo) blacksFilter(blacks []*relation.BlackModel) bson.M {
if len(blacks) == 0 {
return nil
}
or := make(bson.A, 0, len(blacks))
for _, black := range blacks {
or = append(or, b.blackFilter(black.OwnerUserID, black.BlockUserID))
}
return bson.M{"$or": or}
}
func (b *BlackMgo) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) {
return mgoutil.InsertMany(ctx, b.coll, blacks)
}
func (b *BlackMgo) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) {
if len(blacks) == 0 {
return nil
}
return mgoutil.DeleteMany(ctx, b.coll, b.blacksFilter(blacks))
}
func (b *BlackMgo) UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) {
if len(args) == 0 {
return nil
}
return mgoutil.UpdateOne(ctx, b.coll, b.blackFilter(ownerUserID, blockUserID), bson.M{"$set": args}, false)
}
func (b *BlackMgo) Find(ctx context.Context, blacks []*relation.BlackModel) (blackList []*relation.BlackModel, err error) {
return mgoutil.Find[*relation.BlackModel](ctx, b.coll, b.blacksFilter(blacks))
}
func (b *BlackMgo) Take(ctx context.Context, ownerUserID, blockUserID string) (black *relation.BlackModel, err error) {
return mgoutil.FindOne[*relation.BlackModel](ctx, b.coll, b.blackFilter(ownerUserID, blockUserID))
}
func (b *BlackMgo) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) {
return mgoutil.FindPage[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, pagination)
}
func (b *BlackMgo) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) {
if len(userIDs) == 0 {
return mgoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID})
}
return mgoutil.Find[*relation.BlackModel](ctx, b.coll, bson.M{"owner_user_id": ownerUserID, "block_user_id": bson.M{"$in": userIDs}})
}
func (b *BlackMgo) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) {
return mgoutil.Find[string](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, options.Find().SetProjection(bson.M{"_id": 0, "block_user_id": 1}))
}

@ -1,21 +1,32 @@
package newmgo package mgo
import ( import (
"context" "context"
"time"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) {
return &ConversationMgo{ coll := db.Collection("conversation")
coll: db.Collection("conversation"), _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
}, nil Keys: bson.D{
{Key: "owner_user_id", Value: 1},
{Key: "conversation_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &ConversationMgo{coll: coll}, nil
} }
type ConversationMgo struct { type ConversationMgo struct {
@ -23,15 +34,15 @@ type ConversationMgo struct {
} }
func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) { func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) {
return mgotool.InsertMany(ctx, c.coll, conversations) return mgoutil.InsertMany(ctx, c.coll, conversations)
} }
func (c *ConversationMgo) Delete(ctx context.Context, groupIDs []string) (err error) { func (c *ConversationMgo) Delete(ctx context.Context, groupIDs []string) (err error) {
return mgotool.DeleteMany(ctx, c.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) return mgoutil.DeleteMany(ctx, c.coll, bson.M{"group_id": bson.M{"$in": groupIDs}})
} }
func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) { func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) {
res, err := mgotool.UpdateMany(ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": conversationID}, bson.M{"$set": args}) res, err := mgoutil.UpdateMany(ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": conversationID}, bson.M{"$set": args})
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -39,50 +50,55 @@ func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, con
} }
func (c *ConversationMgo) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) { func (c *ConversationMgo) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) {
return mgotool.UpdateOne(ctx, c.coll, bson.M{"owner_user_id": conversation.OwnerUserID, "conversation_id": conversation.ConversationID}, bson.M{"$set": conversation}, true) return mgoutil.UpdateOne(ctx, c.coll, bson.M{"owner_user_id": conversation.OwnerUserID, "conversation_id": conversation.ConversationID}, bson.M{"$set": conversation}, true)
} }
func (c *ConversationMgo) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*relation.ConversationModel, err error) { func (c *ConversationMgo) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*relation.ConversationModel, err error) {
return mgotool.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}}) return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": bson.M{"$in": conversationIDs}})
} }
func (c *ConversationMgo) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) { func (c *ConversationMgo) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) {
return mgotool.Find[string](ctx, c.coll, bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) return mgoutil.Find[string](
ctx,
c.coll,
bson.M{"owner_user_id": bson.M{"$in": userIDs}, "conversation_id": bson.M{"$in": conversationIDs}},
options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}),
)
} }
func (c *ConversationMgo) FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) { func (c *ConversationMgo) FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) {
return mgotool.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) return mgoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1}))
} }
func (c *ConversationMgo) Take(ctx context.Context, userID, conversationID string) (conversation *relation.ConversationModel, err error) { func (c *ConversationMgo) Take(ctx context.Context, userID, conversationID string) (conversation *relation.ConversationModel, err error) {
return mgotool.FindOne[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID}) return mgoutil.FindOne[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": conversationID})
} }
func (c *ConversationMgo) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) { func (c *ConversationMgo) FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) {
return mgotool.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1})) return mgoutil.Find[string](ctx, c.coll, bson.M{"owner_user_id": userID, "conversation_id": bson.M{"$in": conversationIDs}}, options.Find().SetProjection(bson.M{"_id": 0, "conversation_id": 1}))
} }
func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*relation.ConversationModel, err error) { func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*relation.ConversationModel, err error) {
return mgotool.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID}) return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID})
} }
func (c *ConversationMgo) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { func (c *ConversationMgo) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
return mgotool.Find[string](ctx, c.coll, bson.M{"group_id": groupID, "recv_msg_opt": constant.ReceiveNotNotifyMessage}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) return mgoutil.Find[string](ctx, c.coll, bson.M{"group_id": groupID, "recv_msg_opt": constant.ReceiveNotNotifyMessage}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}))
} }
func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) { func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) {
return mgotool.FindOne[int](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": conversationID}, options.FindOne().SetProjection(bson.M{"recv_msg_opt": 1})) return mgoutil.FindOne[int](ctx, c.coll, bson.M{"owner_user_id": ownerUserID, "conversation_id": conversationID}, options.FindOne().SetProjection(bson.M{"recv_msg_opt": 1}))
} }
func (c *ConversationMgo) GetAllConversationIDs(ctx context.Context) ([]string, error) { func (c *ConversationMgo) GetAllConversationIDs(ctx context.Context) ([]string, error) {
return mgotool.Aggregate[string](ctx, c.coll, []bson.M{ return mgoutil.Aggregate[string](ctx, c.coll, []bson.M{
{"$group": bson.M{"_id": "$conversation_id"}}, {"$group": bson.M{"_id": "$conversation_id"}},
{"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}},
}) })
} }
func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) { func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int64, error) {
counts, err := mgotool.Aggregate[int64](ctx, c.coll, []bson.M{ counts, err := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{
{"$group": bson.M{"_id": "$conversation_id"}}, {"$group": bson.M{"_id": "$conversation_id"}},
{"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}},
}) })
@ -96,16 +112,16 @@ func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int6
} }
func (c *ConversationMgo) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) { func (c *ConversationMgo) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) {
return mgotool.FindPageOnly[string](ctx, c.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"conversation_id": 1})) return mgoutil.FindPageOnly[string](ctx, c.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"conversation_id": 1}))
} }
func (c *ConversationMgo) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relation.ConversationModel, error) { func (c *ConversationMgo) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relation.ConversationModel, error) {
return mgotool.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}}) return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"conversation_id": bson.M{"$in": conversationIDs}})
} }
func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relation.ConversationModel, error) { func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relation.ConversationModel, error) {
//"is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)" //"is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)"
return mgotool.Find[*relation.ConversationModel](ctx, c.coll, bson.M{ return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{
"is_msg_destruct": 1, "is_msg_destruct": 1,
"msg_destruct_time": bson.M{"$ne": 0}, "msg_destruct_time": bson.M{"$ne": 0},
"$or": []bson.M{ "$or": []bson.M{
@ -125,5 +141,10 @@ func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([
} }
func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
return mgotool.Find[string](ctx, c.coll, bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$ne": constant.ReceiveMessage}}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1})) return mgoutil.Find[string](
ctx,
c.coll,
bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$ne": constant.ReceiveMessage}},
options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}),
)
} }

@ -1,13 +1,16 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
// FriendMgo implements FriendModelInterface using MongoDB as the storage backend. // FriendMgo implements FriendModelInterface using MongoDB as the storage backend.
@ -17,14 +20,23 @@ type FriendMgo struct {
// NewFriendMongo creates a new instance of FriendMgo with the provided MongoDB database. // NewFriendMongo creates a new instance of FriendMgo with the provided MongoDB database.
func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) {
return &FriendMgo{ coll := db.Collection("friend")
coll: db.Collection(relation.FriendModelCollectionName), _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
}, nil Keys: bson.D{
{Key: "owner_user_id", Value: 1},
{Key: "friend_user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &FriendMgo{coll: coll}, nil
} }
// Create inserts multiple friend records. // Create inserts multiple friend records.
func (f *FriendMgo) Create(ctx context.Context, friends []*relation.FriendModel) error { func (f *FriendMgo) Create(ctx context.Context, friends []*relation.FriendModel) error {
return mgotool.InsertMany(ctx, f.coll, friends) return mgoutil.InsertMany(ctx, f.coll, friends)
} }
// Delete removes specified friends of the owner user. // Delete removes specified friends of the owner user.
@ -33,11 +45,7 @@ func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserID
"owner_user_id": ownerUserID, "owner_user_id": ownerUserID,
"friend_user_id": bson.M{"$in": friendUserIDs}, "friend_user_id": bson.M{"$in": friendUserIDs},
} }
_, err := f.coll.DeleteMany(ctx, filter) return mgoutil.DeleteOne(ctx, f.coll, filter)
if err != nil {
return err
}
return nil
} }
// UpdateByMap updates specific fields of a friend document using a map. // UpdateByMap updates specific fields of a friend document using a map.
@ -49,12 +57,7 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU
"owner_user_id": ownerUserID, "owner_user_id": ownerUserID,
"friend_user_id": friendUserID, "friend_user_id": friendUserID,
} }
update := bson.M{"$set": args} return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true)
err := mgotool.UpdateOne(ctx, f.coll, filter, update, true)
if err != nil {
return err
}
return nil
} }
// Update modifies multiple friend documents. // Update modifies multiple friend documents.
@ -68,8 +71,7 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU
// UpdateRemark updates the remark for a specific friend. // UpdateRemark updates the remark for a specific friend.
func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error { func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error {
args := map[string]interface{}{"remark": remark} return f.UpdateByMap(ctx, ownerUserID, friendUserID, map[string]any{"remark": remark})
return f.UpdateByMap(ctx, ownerUserID, friendUserID, args)
} }
// Take retrieves a single friend document. Returns an error if not found. // Take retrieves a single friend document. Returns an error if not found.
@ -78,11 +80,7 @@ func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string)
"owner_user_id": ownerUserID, "owner_user_id": ownerUserID,
"friend_user_id": friendUserID, "friend_user_id": friendUserID,
} }
friend, err := mgotool.FindOne[*relation.FriendModel](ctx, f.coll, filter) return mgoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter)
if err != nil {
return nil, err
}
return friend, nil
} }
// FindUserState finds the friendship status between two users. // FindUserState finds the friendship status between two users.
@ -93,11 +91,7 @@ func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string)
{"owner_user_id": userID2, "friend_user_id": userID1}, {"owner_user_id": userID2, "friend_user_id": userID1},
}, },
} }
friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
if err != nil {
return nil, err
}
return friends, nil
} }
// FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error.
@ -106,11 +100,7 @@ func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendU
"owner_user_id": ownerUserID, "owner_user_id": ownerUserID,
"friend_user_id": bson.M{"$in": friendUserIDs}, "friend_user_id": bson.M{"$in": friendUserIDs},
} }
friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
if err != nil {
return nil, err
}
return friends, nil
} }
// FindReversalFriends finds users who have added the specified user as a friend. // FindReversalFriends finds users who have added the specified user as a friend.
@ -119,51 +109,23 @@ func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string
"owner_user_id": bson.M{"$in": ownerUserIDs}, "owner_user_id": bson.M{"$in": ownerUserIDs},
"friend_user_id": friendUserID, "friend_user_id": friendUserID,
} }
friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
if err != nil {
return nil, err
}
return friends, nil
} }
// FindOwnerFriends retrieves a paginated list of friends for a given owner. // FindOwnerFriends retrieves a paginated list of friends for a given owner.
func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination, showNumber int32) ([]*relation.FriendModel, int64, error) { func (f *FriendMgo) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) {
filter := bson.M{"owner_user_id": ownerUserID} filter := bson.M{"owner_user_id": ownerUserID}
count, friends, err := mgotool.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination)
if err != nil {
return nil, 0, err
}
return friends, count, nil
} }
// FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination.
func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination.Pagination, showNumber int32) ([]*relation.FriendModel, int64, error) { func (f *FriendMgo) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (int64, []*relation.FriendModel, error) {
filter := bson.M{"friend_user_id": friendUserID} filter := bson.M{"friend_user_id": friendUserID}
count, friends, err := mgotool.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination)
if err != nil {
return nil, 0, err
}
return friends, count, nil
} }
// FindFriendUserIDs retrieves a list of friend user IDs for a given owner. // FindFriendUserIDs retrieves a list of friend user IDs for a given owner.
func (f *FriendMgo) FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { func (f *FriendMgo) FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) {
filter := bson.M{"owner_user_id": ownerUserID} filter := bson.M{"owner_user_id": ownerUserID}
friends := []*relation.FriendModel{} return mgoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1}))
friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter)
if err != nil {
return nil, err
}
friendUserIDs := make([]string, len(friends))
for i, friend := range friends {
friendUserIDs[i] = friend.FriendUserID
}
return friendUserIDs, nil
}
// NewTx creates a new transaction.
func (f *FriendMgo) NewTx(tx any) relation.FriendModelInterface {
panic("not implemented")
return nil
} }

@ -0,0 +1,99 @@
package mgo
import (
"context"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewFriendRequestMongo(db *mongo.Database) (relation.FriendRequestModelInterface, error) {
coll := db.Collection("friend_request")
_, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
Keys: bson.D{
{Key: "from_user_id", Value: 1},
{Key: "to_user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &FriendRequestMgo{coll: coll}, nil
}
type FriendRequestMgo struct {
coll *mongo.Collection
}
func (f *FriendRequestMgo) FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) {
return mgoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"to_user_id": toUserID}, pagination)
}
func (f *FriendRequestMgo) FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*relation.FriendRequestModel, err error) {
return mgoutil.FindPage[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID}, pagination)
}
func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) {
filter := bson.M{"$or": []bson.M{
{"from_user_id": fromUserID, "to_user_id": toUserID},
{"from_user_id": toUserID, "to_user_id": fromUserID},
}}
return mgoutil.Find[*relation.FriendRequestModel](ctx, f.coll, filter)
}
func (f *FriendRequestMgo) Create(ctx context.Context, friendRequests []*relation.FriendRequestModel) error {
return mgoutil.InsertMany(ctx, f.coll, friendRequests)
}
func (f *FriendRequestMgo) Delete(ctx context.Context, fromUserID, toUserID string) (err error) {
return mgoutil.DeleteOne(ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID})
}
func (f *FriendRequestMgo) UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]any) (err error) {
if len(args) == 0 {
return nil
}
return mgoutil.UpdateOne(ctx, f.coll, bson.M{"from_user_id": formUserID, "to_user_id": toUserID}, bson.M{"$set": args}, true)
}
func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
updater := bson.M{}
if friendRequest.HandleResult != 0 {
updater["handle_result"] = friendRequest.HandleResult
}
if friendRequest.ReqMsg != "" {
updater["req_msg"] = friendRequest.ReqMsg
}
if friendRequest.HandlerUserID != "" {
updater["handler_user_id"] = friendRequest.HandlerUserID
}
if friendRequest.HandleMsg != "" {
updater["handle_msg"] = friendRequest.HandleMsg
}
if !friendRequest.HandleTime.IsZero() {
updater["handle_time"] = friendRequest.HandleTime
}
if friendRequest.Ex != "" {
updater["ex"] = friendRequest.Ex
}
if len(updater) == 0 {
return nil
}
filter := bson.M{"from_user_id": friendRequest.FromUserID, "to_user_id": friendRequest.ToUserID}
return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": updater}, true)
}
func (f *FriendRequestMgo) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) {
return mgoutil.FindOne[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID})
}
func (f *FriendRequestMgo) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) {
return f.Find(ctx, fromUserID, toUserID)
}

@ -1,19 +1,30 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"time" "go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) { func NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) {
return &GroupMgo{ coll := db.Collection("group")
coll: db.Collection("group"), _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
}, nil Keys: bson.D{
{Key: "group_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &GroupMgo{coll: coll}, nil
} }
type GroupMgo struct { type GroupMgo struct {
@ -21,7 +32,7 @@ type GroupMgo struct {
} }
func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) { func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) {
return mgotool.InsertMany(ctx, g.coll, groups) return mgoutil.InsertMany(ctx, g.coll, groups)
} }
func (g *GroupMgo) UpdateState(ctx context.Context, groupID string, state int32) (err error) { func (g *GroupMgo) UpdateState(ctx context.Context, groupID string, state int32) (err error) {
@ -32,29 +43,63 @@ func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[strin
if len(args) == 0 { if len(args) == 0 {
return nil return nil
} }
return mgotool.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true) return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true)
} }
func (g *GroupMgo) Find(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) { func (g *GroupMgo) Find(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) {
return mgotool.Find[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}) return mgoutil.Find[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}})
} }
func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.GroupModel, err error) { func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.GroupModel, err error) {
return mgotool.FindOne[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": groupID}) return mgoutil.FindOne[*relation.GroupModel](ctx, g.coll, bson.M{"group_id": groupID})
} }
func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) { func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) {
return mgotool.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword}}, pagination) return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword}}, pagination)
} }
func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) {
if before == nil { if before == nil {
return mgotool.Count(ctx, g.coll, bson.M{}) return mgoutil.Count(ctx, g.coll, bson.M{})
} }
return mgotool.Count(ctx, g.coll, bson.M{"create_time": bson.M{"$lt": before}}) return mgoutil.Count(ctx, g.coll, bson.M{"create_time": bson.M{"$lt": before}})
} }
func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) { func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) {
//TODO implement me pipeline := bson.A{
panic("implement me") bson.M{
"$match": bson.M{
"create_time": bson.M{
"$gte": start,
"$lt": end,
},
},
},
bson.M{
"$group": bson.M{
"_id": bson.M{
"$dateToString": bson.M{
"format": "%Y-%m-%d",
"date": "$create_time",
},
},
"count": bson.M{
"$sum": 1,
},
},
},
}
type Item struct {
Date string `bson:"_id"`
Count int64 `bson:"count"`
}
items, err := mgoutil.Aggregate[Item](ctx, g.coll, pipeline)
if err != nil {
return nil, err
}
res := make(map[string]int64, len(items))
for _, item := range items {
res[item.Date] = item.Count
}
return res, nil
} }

@ -1,18 +1,31 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, error) { func NewGroupMember(db *mongo.Database) (relation.GroupMemberModelInterface, error) {
return &GroupMemberMgo{coll: db.Collection("group_member")}, nil coll := db.Collection("group_member")
_, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
Keys: bson.D{
{Key: "group_id", Value: 1},
{Key: "user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &GroupMemberMgo{coll: coll}, nil
} }
type GroupMemberMgo struct { type GroupMemberMgo struct {
@ -20,11 +33,11 @@ type GroupMemberMgo struct {
} }
func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) { func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) {
return mgotool.InsertMany(ctx, g.coll, groupMembers) return mgoutil.InsertMany(ctx, g.coll, groupMembers)
} }
func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) { func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) {
return mgotool.DeleteMany(ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) return mgoutil.DeleteMany(ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}})
} }
func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error { func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error {
@ -32,7 +45,7 @@ func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, us
} }
func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) { func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) {
return mgotool.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true) return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true)
} }
func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*relation.GroupMemberModel, err error) { func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (groupMembers []*relation.GroupMemberModel, err error) {
@ -41,19 +54,19 @@ func (g *GroupMemberMgo) Find(ctx context.Context, groupIDs []string, userIDs []
} }
func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) { func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) {
return mgotool.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) return mgoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1}))
} }
func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *relation.GroupMemberModel, err error) { func (g *GroupMemberMgo) Take(ctx context.Context, groupID string, userID string) (groupMember *relation.GroupMemberModel, err error) {
return mgotool.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) return mgoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID})
} }
func (g *GroupMemberMgo) TakeOwner(ctx context.Context, groupID string) (groupMember *relation.GroupMemberModel, err error) { func (g *GroupMemberMgo) TakeOwner(ctx context.Context, groupID string) (groupMember *relation.GroupMemberModel, err error) {
return mgotool.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner}) return mgoutil.FindOne[*relation.GroupMemberModel](ctx, g.coll, bson.M{"group_id": groupID, "role_level": constant.GroupOwner})
} }
func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) { func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) {
return mgotool.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) return mgoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1}))
} }
func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*relation.GroupMemberModel, err error) { func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*relation.GroupMemberModel, err error) {
@ -62,11 +75,11 @@ func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, group
} }
func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
return mgotool.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) return mgoutil.Find[string](ctx, g.coll, bson.M{"user_id": userID}, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1}))
} }
func (g *GroupMemberMgo) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) { func (g *GroupMemberMgo) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) {
return mgotool.Count(ctx, g.coll, bson.M{"group_id": groupID}) return mgoutil.Count(ctx, g.coll, bson.M{"group_id": groupID})
} }
func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
@ -76,7 +89,7 @@ func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID stri
"$in": []int{constant.GroupOwner, constant.GroupAdmin}, "$in": []int{constant.GroupOwner, constant.GroupAdmin},
}, },
} }
return mgotool.Find[string](ctx, g.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1})) return mgoutil.Find[string](ctx, g.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1}))
} }
func (g *GroupMemberMgo) IsUpdateRoleLevel(data map[string]any) bool { func (g *GroupMemberMgo) IsUpdateRoleLevel(data map[string]any) bool {

@ -1,16 +1,30 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) { func NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) {
return &GroupRequestMgo{coll: db.Collection("group_request")}, nil coll := db.Collection("group_request")
_, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
Keys: bson.D{
{Key: "group_id", Value: 1},
{Key: "user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &GroupRequestMgo{coll: coll}, nil
} }
type GroupRequestMgo struct { type GroupRequestMgo struct {
@ -18,29 +32,29 @@ type GroupRequestMgo struct {
} }
func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) { func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) {
return mgotool.InsertMany(ctx, g.coll, groupRequests) return mgoutil.InsertMany(ctx, g.coll, groupRequests)
} }
func (g *GroupRequestMgo) Delete(ctx context.Context, groupID string, userID string) (err error) { func (g *GroupRequestMgo) Delete(ctx context.Context, groupID string, userID string) (err error) {
return mgotool.DeleteOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) return mgoutil.DeleteOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID})
} }
func (g *GroupRequestMgo) UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) { func (g *GroupRequestMgo) UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) {
return mgotool.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": bson.M{"handle_msg": handledMsg, "handle_result": handleResult}}, true) return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": bson.M{"handle_msg": handledMsg, "handle_result": handleResult}}, true)
} }
func (g *GroupRequestMgo) Take(ctx context.Context, groupID string, userID string) (groupRequest *relation.GroupRequestModel, err error) { func (g *GroupRequestMgo) Take(ctx context.Context, groupID string, userID string) (groupRequest *relation.GroupRequestModel, err error) {
return mgotool.FindOne[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}) return mgoutil.FindOne[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID})
} }
func (g *GroupRequestMgo) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relation.GroupRequestModel, error) { func (g *GroupRequestMgo) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relation.GroupRequestModel, error) {
return mgotool.Find[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}}) return mgoutil.Find[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": groupID, "user_id": bson.M{"$in": userIDs}})
} }
func (g *GroupRequestMgo) Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { func (g *GroupRequestMgo) Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) {
return mgotool.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"user_id": userID}, pagination) return mgoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"user_id": userID}, pagination)
} }
func (g *GroupRequestMgo) PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) { func (g *GroupRequestMgo) PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*relation.GroupRequestModel, err error) {
return mgotool.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination) return mgoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination)
} }

@ -0,0 +1,70 @@
package mgo
import (
"context"
"time"
"github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
func NewLogMongo(db *mongo.Database) (relation.LogInterface, error) {
coll := db.Collection("log")
_, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
{
Keys: bson.D{
{Key: "log_id", Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: "user_id", Value: 1},
},
},
{
Keys: bson.D{
{Key: "create_time", Value: -1},
},
},
})
if err != nil {
return nil, err
}
return &LogMgo{coll: coll}, nil
}
type LogMgo struct {
coll *mongo.Collection
}
func (l *LogMgo) Create(ctx context.Context, log []*relation.LogModel) error {
return mgoutil.InsertMany(ctx, l.coll, log)
}
func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) {
filter := bson.M{"create_time": bson.M{"$gte": start, "$lte": end}}
if keyword != "" {
filter["user_id"] = bson.M{"$regex": keyword}
}
return mgoutil.FindPage[*relation.LogModel](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1}))
}
func (l *LogMgo) Delete(ctx context.Context, logID []string, userID string) error {
if userID == "" {
return mgoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}})
}
return mgoutil.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}, "user_id": userID})
}
func (l *LogMgo) Get(ctx context.Context, logIDs []string, userID string) ([]*relation.LogModel, error) {
if userID == "" {
return mgoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}})
}
return mgoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID})
}

@ -1,18 +1,28 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/OpenIMSDK/tools/mgoutil"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) { func NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) {
return &S3Mongo{ coll := db.Collection("s3")
coll: db.Collection("s3"), _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
}, nil Keys: bson.D{
{Key: "name", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &S3Mongo{coll: coll}, nil
} }
type S3Mongo struct { type S3Mongo struct {
@ -30,16 +40,16 @@ func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) erro
"group": obj.Group, "group": obj.Group,
"create_time": obj.CreateTime, "create_time": obj.CreateTime,
} }
return mgotool.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true)) return mgoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true))
} }
func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*relation.ObjectModel, error) { func (o *S3Mongo) Take(ctx context.Context, engine string, name string) (*relation.ObjectModel, error) {
if engine == "" { if engine == "" {
return mgotool.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name}) return mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name})
} }
return mgotool.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine}) return mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine})
} }
func (o *S3Mongo) Delete(ctx context.Context, engine string, name string) error { func (o *S3Mongo) Delete(ctx context.Context, engine string, name string) error {
return mgotool.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) return mgoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine})
} }

@ -1,20 +1,30 @@
package newmgo package mgo
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "github.com/OpenIMSDK/tools/mgoutil"
"github.com/OpenIMSDK/tools/pagination"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) {
return &UserMgo{ coll := db.Collection("user")
coll: db.Collection("user"), _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
}, nil Keys: bson.D{
{Key: "user_id", Value: 1},
},
Options: options.Index().SetUnique(true),
})
if err != nil {
return nil, err
}
return &UserMgo{coll: coll}, nil
} }
type UserMgo struct { type UserMgo struct {
@ -22,50 +32,82 @@ type UserMgo struct {
} }
func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error { func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error {
return mgotool.InsertMany(ctx, u.coll, users) return mgoutil.InsertMany(ctx, u.coll, users)
} }
func (u *UserMgo) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) { func (u *UserMgo) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) {
if len(args) == 0 { if len(args) == 0 {
return nil return nil
} }
return mgotool.UpdateOne(ctx, u.coll, bson.M{"user_id": userID}, bson.M{"$set": args}, true) return mgoutil.UpdateOne(ctx, u.coll, bson.M{"user_id": userID}, bson.M{"$set": args}, true)
} }
func (u *UserMgo) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { func (u *UserMgo) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
return mgotool.Find[*relation.UserModel](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"user_id": bson.M{"$in": userIDs}})
} }
func (u *UserMgo) Take(ctx context.Context, userID string) (user *relation.UserModel, err error) { func (u *UserMgo) Take(ctx context.Context, userID string) (user *relation.UserModel, err error) {
return mgotool.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID}) return mgoutil.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID})
} }
func (u *UserMgo) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { func (u *UserMgo) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) {
return mgotool.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination) return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination)
} }
func (u *UserMgo) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) { func (u *UserMgo) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) {
return mgotool.FindPage[string](ctx, u.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"user_id": 1})) return mgoutil.FindPage[string](ctx, u.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"user_id": 1}))
} }
func (u *UserMgo) Exist(ctx context.Context, userID string) (exist bool, err error) { func (u *UserMgo) Exist(ctx context.Context, userID string) (exist bool, err error) {
return mgotool.Exist(ctx, u.coll, bson.M{"user_id": userID}) return mgoutil.Exist(ctx, u.coll, bson.M{"user_id": userID})
} }
func (u *UserMgo) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) { func (u *UserMgo) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
return mgotool.FindOne[int](ctx, u.coll, bson.M{"user_id": userID}, options.FindOne().SetProjection(bson.M{"global_recv_msg_opt": 1})) return mgoutil.FindOne[int](ctx, u.coll, bson.M{"user_id": userID}, options.FindOne().SetProjection(bson.M{"global_recv_msg_opt": 1}))
} }
func (u *UserMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { func (u *UserMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) {
return mgotool.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}}) if before == nil {
return mgoutil.Count(ctx, u.coll, bson.M{})
}
return mgoutil.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}})
} }
func (u *UserMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) { func (u *UserMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) {
//type Temp struct { pipeline := bson.A{
// CreateTime time.Time `bson:"create_time"` bson.M{
// Number int64 `bson:"number"` "$match": bson.M{
//} "create_time": bson.M{
//mgotool.Find(ctx, u.coll, bson.M{"create_time": bson.M{"$gte": start, "$lt": end}}, options.Find().SetProjection(bson.M{"create_time": 1})) "$gte": start,
panic("implement me") "$lt": end,
return nil, nil },
},
},
bson.M{
"$group": bson.M{
"_id": bson.M{
"$dateToString": bson.M{
"format": "%Y-%m-%d",
"date": "$create_time",
},
},
"count": bson.M{
"$sum": 1,
},
},
},
}
type Item struct {
Date string `bson:"_id"`
Count int64 `bson:"count"`
}
items, err := mgoutil.Aggregate[Item](ctx, u.coll, pipeline)
if err != nil {
return nil, err
}
res := make(map[string]int64, len(items))
for _, item := range items {
res[item.Date] = item.Count
}
return res, nil
} }

@ -1,48 +0,0 @@
package newmgo
import (
"context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
type FriendRequestMgo struct {
coll *mongo.Collection
}
func NewFriendRequestMongo(db *mongo.Database) (relation.FriendRequestModelInterface, error) {
return &FriendRequestMgo{
coll: db.Collection(relation.FriendRequestModelCollectionName),
}, nil
}
func (f *FriendRequestMgo) Create(ctx context.Context, friendRequests []*relation.FriendRequestModel) error {
return mgotool.InsertMany(ctx, f.coll, friendRequests)
}
func (f *FriendRequestMgo) Delete(ctx context.Context, fromUserID, toUserID string) (err error) {
return mgotool.Delete[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID})
}
func (f *FriendRequestMgo) UpdateByMap(ctx context.Context, formUserID, toUserID string, args map[string]any) (err error) {
if len(args) == 0 {
return nil
}
return mgotool.UpdateOne(ctx, f.coll, bson.M{"from_user_id": formUserID, "to_user_id": toUserID}, bson.M{"$set": args}, true)
}
func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
return mgotool.UpdateOne(ctx, f.coll, bson.M{"_id": friendRequest.ID}, bson.M{"$set": friendRequest}, true)
}
func (f *FriendRequestMgo) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) {
return mgotool.FindOne[*relation.FriendRequestModel](ctx, f.coll, bson.M{"from_user_id": fromUserID, "to_user_id": toUserID})
}
func (f *FriendRequestMgo) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *relation.FriendRequestModel, err error) {
return f.Find(ctx, fromUserID, toUserID)
}

@ -1,49 +0,0 @@
package newmgo
import (
"context"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/newmgo/mgotool"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"time"
)
func NewLogMongo(db *mongo.Database) (relation.LogInterface, error) {
lm := &LogMgo{
coll: db.Collection("log"),
}
return lm, nil
}
type LogMgo struct {
coll *mongo.Collection
}
func (l *LogMgo) Create(ctx context.Context, log []*relation.Log) error {
return mgotool.InsertMany(ctx, l.coll, log)
}
func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.Log, error) {
filter := bson.M{"create_time": bson.M{"$gte": start, "$lte": end}}
if keyword != "" {
filter["user_id"] = bson.M{"$regex": keyword}
}
return mgotool.FindPage[*relation.Log](ctx, l.coll, filter, pagination, options.Find().SetSort(bson.M{"create_time": -1}))
}
func (l *LogMgo) Delete(ctx context.Context, logID []string, userID string) error {
if userID == "" {
return mgotool.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}})
}
return mgotool.DeleteMany(ctx, l.coll, bson.M{"log_id": bson.M{"$in": logID}, "user_id": userID})
}
func (l *LogMgo) Get(ctx context.Context, logIDs []string, userID string) ([]*relation.Log, error) {
if userID == "" {
return mgotool.Find[*relation.Log](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}})
}
return mgotool.Find[*relation.Log](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID})
}

@ -1,198 +0,0 @@
package mgotool
import (
"context"
"github.com/OpenIMSDK/tools/errs"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func basic[T any]() bool {
var t T
switch any(t).(type) {
case int:
case int8:
case int16:
case int32:
case int64:
case uint:
case uint8:
case uint16:
case uint32:
case uint64:
case float32:
case float64:
case string:
case []byte:
default:
return false
}
return true
}
func anes[T any](ts []T) []any {
val := make([]any, len(ts))
for i := range ts {
val[i] = ts[i]
}
return val
}
func findOptionToCountOption(opts []*options.FindOptions) *options.CountOptions {
countOpt := options.Count()
for _, opt := range opts {
if opt.Skip != nil {
countOpt.SetSkip(*opt.Skip)
}
if opt.Limit != nil {
countOpt.SetLimit(*opt.Limit)
}
}
return countOpt
}
func InsertMany[T any](ctx context.Context, coll *mongo.Collection, val []T, opts ...*options.InsertManyOptions) error {
_, err := coll.InsertMany(ctx, anes(val), opts...)
if err != nil {
return errs.Wrap(err)
}
return nil
}
func UpdateOne(ctx context.Context, coll *mongo.Collection, filter any, update any, notMatchedErr bool, opts ...*options.UpdateOptions) error {
res, err := coll.UpdateOne(ctx, filter, update, opts...)
if err != nil {
return errs.Wrap(err)
}
if notMatchedErr && res.MatchedCount == 0 {
return errs.Wrap(mongo.ErrNoDocuments)
}
return nil
}
func UpdateMany(ctx context.Context, coll *mongo.Collection, filter any, update any, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
res, err := coll.UpdateMany(ctx, filter, update, opts...)
if err != nil {
return nil, errs.Wrap(err)
}
return res, nil
}
func Find[T any](ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.FindOptions) ([]T, error) {
cur, err := coll.Find(ctx, filter, opts...)
if err != nil {
return nil, errs.Wrap(err)
}
defer cur.Close(ctx)
var res []T
if basic[T]() {
var temp []map[string]T
if err := cur.All(ctx, &temp); err != nil {
return nil, errs.Wrap(err)
}
res = make([]T, 0, len(temp))
for _, m := range temp {
if len(m) != 1 {
return nil, errs.ErrInternalServer.Wrap("mongo find result len(m) != 1")
}
for _, t := range m {
res = append(res, t)
}
}
} else {
if err := cur.All(ctx, &res); err != nil {
return nil, errs.Wrap(err)
}
}
return res, nil
}
func FindOne[T any](ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.FindOneOptions) (res T, err error) {
cur := coll.FindOne(ctx, filter, opts...)
if err := cur.Err(); err != nil {
return res, errs.Wrap(err)
}
if err := cur.Decode(&res); err != nil {
return res, errs.Wrap(err)
}
return res, nil
}
func FindPage[T any](ctx context.Context, coll *mongo.Collection, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) (int64, []T, error) {
count, err := Count(ctx, coll, filter, findOptionToCountOption(opts))
if err != nil {
return 0, nil, err
}
if count == 0 || pagination == nil {
return count, nil, nil
}
skip := int64(pagination.GetPageNumber()-1) * int64(pagination.GetShowNumber())
if skip < 0 || skip >= count || pagination.GetShowNumber() <= 0 {
return count, nil, nil
}
opt := options.Find().SetSkip(skip).SetLimit(int64(pagination.GetShowNumber()))
res, err := Find[T](ctx, coll, filter, append(opts, opt)...)
if err != nil {
return 0, nil, err
}
return count, res, nil
}
func FindPageOnly[T any](ctx context.Context, coll *mongo.Collection, filter any, pagination pagination.Pagination, opts ...*options.FindOptions) ([]T, error) {
skip := int64(pagination.GetPageNumber()-1) * int64(pagination.GetShowNumber())
if skip < 0 || pagination.GetShowNumber() <= 0 {
return nil, nil
}
opt := options.Find().SetSkip(skip).SetLimit(int64(pagination.GetShowNumber()))
return Find[T](ctx, coll, filter, append(opts, opt)...)
}
func Count(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.CountOptions) (int64, error) {
return coll.CountDocuments(ctx, filter, opts...)
}
func Exist(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.CountOptions) (bool, error) {
opts = append(opts, options.Count().SetLimit(1))
count, err := Count(ctx, coll, filter, opts...)
if err != nil {
return false, err
}
return count > 0, nil
}
func DeleteOne(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) error {
if _, err := coll.DeleteOne(ctx, filter, opts...); err != nil {
return errs.Wrap(err)
}
return nil
}
func DeleteMany(ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) error {
if _, err := coll.DeleteMany(ctx, filter, opts...); err != nil {
return errs.Wrap(err)
}
return nil
}
// TODO
func Delete[T any](ctx context.Context, coll *mongo.Collection, filter any, opts ...*options.DeleteOptions) error {
if _, err := coll.DeleteMany(ctx, filter, opts...); err != nil {
return errs.Wrap(err)
}
return nil
}
func Aggregate[T any](ctx context.Context, coll *mongo.Collection, pipeline any, opts ...*options.AggregateOptions) ([]T, error) {
cur, err := coll.Aggregate(ctx, pipeline, opts...)
if err != nil {
return nil, err
}
var ts []T
if err := cur.All(ctx, &ts); err != nil {
return nil, err
}
return ts, nil
}

@ -1,111 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"context"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/ormutil"
"gorm.io/gorm"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
type BlackGorm struct {
*MetaDB
}
func NewBlackGorm(db *gorm.DB) relation.BlackModelInterface {
return &BlackGorm{NewMetaDB(db, &relation.BlackModel{})}
}
func (b *BlackGorm) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) {
return utils.Wrap(b.db(ctx).Create(&blacks).Error, "")
}
func (b *BlackGorm) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) {
return utils.Wrap(b.db(ctx).Delete(blacks).Error, "")
}
func (b *BlackGorm) UpdateByMap(
ctx context.Context,
ownerUserID, blockUserID string,
args map[string]any,
) (err error) {
return utils.Wrap(
b.db(ctx).Where("block_user_id = ? and block_user_id = ?", ownerUserID, blockUserID).Updates(args).Error,
"",
)
}
func (b *BlackGorm) Update(ctx context.Context, blacks []*relation.BlackModel) (err error) {
return utils.Wrap(b.db(ctx).Updates(&blacks).Error, "")
}
func (b *BlackGorm) Find(
ctx context.Context,
blacks []*relation.BlackModel,
) (blackList []*relation.BlackModel, err error) {
var where [][]any
for _, black := range blacks {
where = append(where, []any{black.OwnerUserID, black.BlockUserID})
}
return blackList, utils.Wrap(
b.db(ctx).Where("(owner_user_id, block_user_id) in ?", where).Find(&blackList).Error,
"",
)
}
func (b *BlackGorm) Take(ctx context.Context, ownerUserID, blockUserID string) (black *relation.BlackModel, err error) {
black = &relation.BlackModel{}
return black, utils.Wrap(
b.db(ctx).Where("owner_user_id = ? and block_user_id = ?", ownerUserID, blockUserID).Take(black).Error,
"",
)
}
func (b *BlackGorm) FindOwnerBlacks(
ctx context.Context,
ownerUserID string,
pageNumber, showNumber int32,
) (blacks []*relation.BlackModel, total int64, err error) {
err = b.db(ctx).Count(&total).Error
if err != nil {
return nil, 0, utils.Wrap(err, "")
}
totalUint32, blacks, err := ormutil.GormPage[relation.BlackModel](
b.db(ctx).Where("owner_user_id = ?", ownerUserID),
pageNumber,
showNumber,
)
total = int64(totalUint32)
return
}
func (b *BlackGorm) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) {
return blackUserIDs, utils.Wrap(
b.db(ctx).Where("owner_user_id = ?", ownerUserID).Pluck("block_user_id", &blackUserIDs).Error,
"",
)
}
func (b *BlackGorm) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*relation.BlackModel, err error) {
return blacks, errs.Wrap(b.db(ctx).Where("owner_user_id = ? and block_user_id in ?", ownerUserID, userIDs).Find(&blacks).Error)
}

@ -1,63 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"github.com/golang/protobuf/jsonpb"
"github.com/jinzhu/copier"
"google.golang.org/protobuf/proto"
"gorm.io/gorm"
"github.com/OpenIMSDK/protocol/constant"
pbmsg "github.com/OpenIMSDK/protocol/msg"
sdkws "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
type ChatLogGorm struct {
*MetaDB
}
func NewChatLogGorm(db *gorm.DB) relation.ChatLogModelInterface {
return &ChatLogGorm{NewMetaDB(db, &relation.ChatLogModel{})}
}
func (c *ChatLogGorm) Create(msg *pbmsg.MsgDataToMQ) error {
chatLog := new(relation.ChatLogModel)
copier.Copy(chatLog, msg.MsgData)
switch msg.MsgData.SessionType {
case constant.GroupChatType, constant.SuperGroupChatType:
chatLog.RecvID = msg.MsgData.GroupID
case constant.SingleChatType:
chatLog.RecvID = msg.MsgData.RecvID
}
if msg.MsgData.ContentType >= constant.NotificationBegin && msg.MsgData.ContentType <= constant.NotificationEnd {
var tips sdkws.TipsComm
_ = proto.Unmarshal(msg.MsgData.Content, &tips)
marshaler := jsonpb.Marshaler{
OrigName: true,
EnumsAsInts: false,
EmitDefaults: false,
}
chatLog.Content, _ = marshaler.MarshalToString(&tips)
} else {
chatLog.Content = string(msg.MsgData.Content)
}
chatLog.CreateTime = utils.UnixMillSecondToTime(msg.MsgData.CreateTime)
chatLog.SendTime = utils.UnixMillSecondToTime(msg.MsgData.SendTime)
return c.DB.Create(chatLog).Error
}

@ -1,244 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//
//import (
// "context"
//
// "github.com/OpenIMSDK/tools/errs"
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/protocol/constant"
// "github.com/OpenIMSDK/tools/utils"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//type ConversationGorm struct {
// *MetaDB
//}
//
//func NewConversationGorm(db *gorm.DB) relation.ConversationModelInterface {
// return &ConversationGorm{NewMetaDB(db, &relation.ConversationModel{})}
//}
//
//func (c *ConversationGorm) NewTx(tx any) relation.ConversationModelInterface {
// return &ConversationGorm{NewMetaDB(tx.(*gorm.DB), &relation.ConversationModel{})}
//}
//
//func (c *ConversationGorm) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) {
// return utils.Wrap(c.db(ctx).Create(&conversations).Error, "")
//}
//
//func (c *ConversationGorm) Delete(ctx context.Context, groupIDs []string) (err error) {
// return utils.Wrap(c.db(ctx).Where("group_id in (?)", groupIDs).Delete(&relation.ConversationModel{}).Error, "")
//}
//
//func (c *ConversationGorm) UpdateByMap(
// ctx context.Context,
// userIDList []string,
// conversationID string,
// args map[string]any,
//) (rows int64, err error) {
// result := c.db(ctx).Where("owner_user_id IN (?) and conversation_id=?", userIDList, conversationID).Updates(args)
// return result.RowsAffected, utils.Wrap(result.Error, "")
//}
//
//func (c *ConversationGorm) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) {
// return utils.Wrap(
// c.db(ctx).
// Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID).
// Updates(conversation).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) Find(
// ctx context.Context,
// ownerUserID string,
// conversationIDs []string,
//) (conversations []*relation.ConversationModel, err error) {
// err = utils.Wrap(
// c.db(ctx).
// Where("owner_user_id=? and conversation_id IN (?)", ownerUserID, conversationIDs).
// Find(&conversations).
// Error,
// "",
// )
// return conversations, err
//}
//
//func (c *ConversationGorm) Take(
// ctx context.Context,
// userID, conversationID string,
//) (conversation *relation.ConversationModel, err error) {
// cc := &relation.ConversationModel{}
// return cc, utils.Wrap(
// c.db(ctx).Where("conversation_id = ? And owner_user_id = ?", conversationID, userID).Take(cc).Error,
// "",
// )
//}
//
//func (c *ConversationGorm) FindUserID(
// ctx context.Context,
// userIDs []string,
// conversationIDs []string,
//) (existUserID []string, err error) {
// return existUserID, utils.Wrap(
// c.db(ctx).
// Where(" owner_user_id IN (?) and conversation_id in (?)", userIDs, conversationIDs).
// Pluck("owner_user_id", &existUserID).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) FindConversationID(
// ctx context.Context,
// userID string,
// conversationIDList []string,
//) (existConversationID []string, err error) {
// return existConversationID, utils.Wrap(
// c.db(ctx).
// Where(" conversation_id IN (?) and owner_user_id=?", conversationIDList, userID).
// Pluck("conversation_id", &existConversationID).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) FindUserIDAllConversationID(
// ctx context.Context,
// userID string,
//) (conversationIDList []string, err error) {
// return conversationIDList, utils.Wrap(
// c.db(ctx).Where("owner_user_id=?", userID).Pluck("conversation_id", &conversationIDList).Error,
// "",
// )
//}
//
//func (c *ConversationGorm) FindUserIDAllConversations(
// ctx context.Context,
// userID string,
//) (conversations []*relation.ConversationModel, err error) {
// return conversations, utils.Wrap(c.db(ctx).Where("owner_user_id=?", userID).Find(&conversations).Error, "")
//}
//
//func (c *ConversationGorm) FindRecvMsgNotNotifyUserIDs(
// ctx context.Context,
// groupID string,
//) (userIDs []string, err error) {
// return userIDs, utils.Wrap(
// c.db(ctx).
// Where("group_id = ? and recv_msg_opt = ?", groupID, constant.ReceiveNotNotifyMessage).
// Pluck("owner_user_id", &userIDs).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) FindSuperGroupRecvMsgNotNotifyUserIDs(
// ctx context.Context,
// groupID string,
//) (userIDs []string, err error) {
// return userIDs, utils.Wrap(
// c.db(ctx).
// Where("group_id = ? and recv_msg_opt = ? and conversation_type = ?", groupID, constant.ReceiveNotNotifyMessage, constant.SuperGroupChatType).
// Pluck("owner_user_id", &userIDs).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) GetUserRecvMsgOpt(
// ctx context.Context,
// ownerUserID, conversationID string,
//) (opt int, err error) {
// var conversation relation.ConversationModel
// return int(
// conversation.RecvMsgOpt,
// ), utils.Wrap(
// c.db(ctx).
// Where("conversation_id = ? And owner_user_id = ?", conversationID, ownerUserID).
// Select("recv_msg_opt").
// Find(&conversation).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) GetAllConversationIDs(ctx context.Context) (conversationIDs []string, err error) {
// return conversationIDs, utils.Wrap(
// c.db(ctx).Distinct("conversation_id").Pluck("conversation_id", &conversationIDs).Error,
// "",
// )
//}
//
//func (c *ConversationGorm) GetAllConversationIDsNumber(ctx context.Context) (int64, error) {
// var num int64
// err := c.db(ctx).Select("COUNT(DISTINCT conversation_id)").Model(&relation.ConversationModel{}).Count(&num).Error
// return num, errs.Wrap(err)
//}
//
//func (c *ConversationGorm) PageConversationIDs(ctx context.Context, pageNumber, showNumber int32) (conversationIDs []string, err error) {
// err = c.db(ctx).Distinct("conversation_id").Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("conversation_id", &conversationIDs).Error
// err = errs.Wrap(err)
// return
//}
//
//func (c *ConversationGorm) GetConversationsByConversationID(
// ctx context.Context,
// conversationIDs []string,
//) (conversations []*relation.ConversationModel, err error) {
// return conversations, utils.Wrap(
// c.db(ctx).Where("conversation_id IN (?)", conversationIDs).Find(&conversations).Error,
// "",
// )
//}
//
//func (c *ConversationGorm) GetConversationIDsNeedDestruct(
// ctx context.Context,
//) (conversations []*relation.ConversationModel, err error) {
// return conversations, utils.Wrap(
// c.db(ctx).
// Where("is_msg_destruct = 1 && msg_destruct_time != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)").
// Find(&conversations).
// Error,
// "",
// )
//}
//
//func (c *ConversationGorm) GetConversationRecvMsgOpt(ctx context.Context, userID string, conversationID string) (int32, error) {
// var recvMsgOpt int32
// return recvMsgOpt, errs.Wrap(
// c.db(ctx).
// Model(&relation.ConversationModel{}).
// Where("conversation_id = ? and owner_user_id in ?", conversationID, userID).
// Pluck("recv_msg_opt", &recvMsgOpt).
// Error,
// )
//}
//
//func (c *ConversationGorm) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
// var userIDs []string
// return userIDs, errs.Wrap(
// c.db(ctx).
// Model(&relation.ConversationModel{}).
// Where("conversation_id = ? and recv_msg_opt <> ?", conversationID, constant.ReceiveMessage).
// Pluck("owner_user_id", &userIDs).Error,
// )
//}

@ -1,15 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"

@ -1,193 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"context"
"gorm.io/gorm"
"github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
)
type FriendGorm struct {
*MetaDB
}
func NewFriendGorm(db *gorm.DB) relation.FriendModelInterface {
return &FriendGorm{NewMetaDB(db, &relation.FriendModel{})}
}
func (f *FriendGorm) NewTx(tx any) relation.FriendModelInterface {
return &FriendGorm{NewMetaDB(tx.(*gorm.DB), &relation.FriendModel{})}
}
// 插入多条记录.
func (f *FriendGorm) Create(ctx context.Context, friends []*relation.FriendModel) (err error) {
return utils.Wrap(f.db(ctx).Create(&friends).Error, "")
}
// 删除ownerUserID指定的好友.
func (f *FriendGorm) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) {
err = utils.Wrap(
f.db(ctx).
Where("owner_user_id = ? AND friend_user_id in ( ?)", ownerUserID, friendUserIDs).
Delete(&relation.FriendModel{}).
Error,
"",
)
return err
}
// 更新ownerUserID单个好友信息 更新零值.
func (f *FriendGorm) UpdateByMap(
ctx context.Context,
ownerUserID string,
friendUserID string,
args map[string]any,
) (err error) {
return utils.Wrap(
f.db(ctx).Where("owner_user_id = ? AND friend_user_id = ? ", ownerUserID, friendUserID).Updates(args).Error,
"",
)
}
// 更新好友信息的非零值.
func (f *FriendGorm) Update(ctx context.Context, friends []*relation.FriendModel) (err error) {
return utils.Wrap(f.db(ctx).Updates(&friends).Error, "")
}
// 更新好友备注(也支持零值 .
func (f *FriendGorm) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) {
if remark != "" {
return utils.Wrap(
f.db(ctx).
Where("owner_user_id = ? and friend_user_id = ?", ownerUserID, friendUserID).
Update("remark", remark).
Error,
"",
)
}
m := make(map[string]any, 1)
m["remark"] = ""
return utils.Wrap(f.db(ctx).Where("owner_user_id = ?", ownerUserID).Updates(m).Error, "")
}
// 获取单个好友信息,如没找到 返回错误.
func (f *FriendGorm) Take(
ctx context.Context,
ownerUserID, friendUserID string,
) (friend *relation.FriendModel, err error) {
friend = &relation.FriendModel{}
return friend, utils.Wrap(
f.db(ctx).Where("owner_user_id = ? and friend_user_id", ownerUserID, friendUserID).Take(friend).Error,
"",
)
}
// 查找好友关系,如果是双向关系,则都返回.
func (f *FriendGorm) FindUserState(
ctx context.Context,
userID1, userID2 string,
) (friends []*relation.FriendModel, err error) {
return friends, utils.Wrap(
f.db(ctx).
Where("(owner_user_id = ? and friend_user_id = ?) or (owner_user_id = ? and friend_user_id = ?)", userID1, userID2, userID2, userID1).
Find(&friends).
Error,
"",
)
}
// 获取 owner指定的好友列表 如果有friendUserIDs不存在也不返回错误.
func (f *FriendGorm) FindFriends(
ctx context.Context,
ownerUserID string,
friendUserIDs []string,
) (friends []*relation.FriendModel, err error) {
return friends, utils.Wrap(
f.db(ctx).Where("owner_user_id = ? AND friend_user_id in (?)", ownerUserID, friendUserIDs).Find(&friends).Error,
"",
)
}
// 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在也不返回错误.
func (f *FriendGorm) FindReversalFriends(
ctx context.Context,
friendUserID string,
ownerUserIDs []string,
) (friends []*relation.FriendModel, err error) {
return friends, utils.Wrap(
f.db(ctx).Where("friend_user_id = ? AND owner_user_id in (?)", friendUserID, ownerUserIDs).Find(&friends).Error,
"",
)
}
// 获取ownerUserID好友列表 支持翻页.
func (f *FriendGorm) FindOwnerFriends(
ctx context.Context,
ownerUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error) {
err = f.DB.Model(&relation.FriendModel{}).Where("owner_user_id = ? ", ownerUserID).Count(&total).Error
if err != nil {
return nil, 0, utils.Wrap(err, "")
}
err = utils.Wrap(
f.db(ctx).
Where("owner_user_id = ? ", ownerUserID).
Limit(int(showNumber)).
Offset(int((pageNumber-1)*showNumber)).
Find(&friends).
Error,
"",
)
return
}
// 获取哪些人添加了friendUserID 支持翻页.
func (f *FriendGorm) FindInWhoseFriends(
ctx context.Context,
friendUserID string,
pageNumber, showNumber int32,
) (friends []*relation.FriendModel, total int64, err error) {
err = f.DB.Model(&relation.FriendModel{}).Where("friend_user_id = ? ", friendUserID).Count(&total).Error
if err != nil {
return nil, 0, utils.Wrap(err, "")
}
err = utils.Wrap(
f.db(ctx).
Where("friend_user_id = ? ", friendUserID).
Limit(int(showNumber)).
Offset(int((pageNumber-1)*showNumber)).
Find(&friends).
Error,
"",
)
return
}
func (f *FriendGorm) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) {
return friendUserIDs, utils.Wrap(
f.db(ctx).
Model(&relation.FriendModel{}).
Where("owner_user_id = ? ", ownerUserID).
Pluck("friend_user_id", &friendUserIDs).
Error,
"",
)
}

@ -1,154 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
// type FriendRequestGorm struct {
// *MetaDB
// }
// func NewFriendRequestGorm(db *gorm.DB) relation.FriendRequestModelInterface {
// return &FriendRequestGorm{NewMetaDB(db, &relation.FriendRequestModel{})}
// }
// func (f *FriendRequestGorm) NewTx(tx any) relation.FriendRequestModelInterface {
// return &FriendRequestGorm{NewMetaDB(tx.(*gorm.DB), &relation.FriendRequestModel{})}
// }
// // 插入多条记录.
// func (f *FriendRequestGorm) Create(ctx context.Context, friendRequests []*relation.FriendRequestModel) (err error) {
// return utils.Wrap(f.db(ctx).Create(&friendRequests).Error, "")
// }
// // 删除记录.
// func (f *FriendRequestGorm) Delete(ctx context.Context, fromUserID, toUserID string) (err error) {
// return utils.Wrap(
// f.db(ctx).
// Where("from_user_id = ? AND to_user_id = ?", fromUserID, toUserID).
// Delete(&relation.FriendRequestModel{}).
// Error,
// "",
// )
// }
// // 更新零值.
// func (f *FriendRequestGorm) UpdateByMap(
// ctx context.Context,
// fromUserID string,
// toUserID string,
// args map[string]any,
// ) (err error) {
// return utils.Wrap(
// f.db(ctx).
// Model(&relation.FriendRequestModel{}).
// Where("from_user_id = ? AND to_user_id =?", fromUserID, toUserID).
// Updates(args).
// Error,
// "",
// )
// }
// // 更新记录 (非零值).
// func (f *FriendRequestGorm) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
// fr2 := *friendRequest
// fr2.FromUserID = ""
// fr2.ToUserID = ""
// return utils.Wrap(
// f.db(ctx).
// Where("from_user_id = ? AND to_user_id =?", friendRequest.FromUserID, friendRequest.ToUserID).
// Updates(fr2).
// Error,
// "",
// )
// }
// // 获取来指定用户的好友申请 未找到 不返回错误.
// func (f *FriendRequestGorm) Find(
// ctx context.Context,
// fromUserID, toUserID string,
// ) (friendRequest *relation.FriendRequestModel, err error) {
// friendRequest = &relation.FriendRequestModel{}
// err = utils.Wrap(
// f.db(ctx).Where("from_user_id = ? and to_user_id = ?", fromUserID, toUserID).Find(friendRequest).Error,
// "",
// )
// return friendRequest, err
// }
// func (f *FriendRequestGorm) Take(
// ctx context.Context,
// fromUserID, toUserID string,
// ) (friendRequest *relation.FriendRequestModel, err error) {
// friendRequest = &relation.FriendRequestModel{}
// err = utils.Wrap(
// f.db(ctx).Where("from_user_id = ? and to_user_id = ?", fromUserID, toUserID).Take(friendRequest).Error,
// "",
// )
// return friendRequest, err
// }
// // 获取toUserID收到的好友申请列表.
// func (f *FriendRequestGorm) FindToUserID(
// ctx context.Context,
// toUserID string,
// pageNumber, showNumber int32,
// ) (friendRequests []*relation.FriendRequestModel, total int64, err error) {
// err = f.db(ctx).Model(&relation.FriendRequestModel{}).Where("to_user_id = ? ", toUserID).Count(&total).Error
// if err != nil {
// return nil, 0, utils.Wrap(err, "")
// }
// err = utils.Wrap(
// f.db(ctx).
// Where("to_user_id = ? ", toUserID).
// Limit(int(showNumber)).
// Offset(int(pageNumber-1)*int(showNumber)).
// Find(&friendRequests).
// Error,
// "",
// )
// return
// }
// // 获取fromUserID发出去的好友申请列表.
// func (f *FriendRequestGorm) FindFromUserID(
// ctx context.Context,
// fromUserID string,
// pageNumber, showNumber int32,
// ) (friendRequests []*relation.FriendRequestModel, total int64, err error) {
// err = f.db(ctx).Model(&relation.FriendRequestModel{}).Where("from_user_id = ? ", fromUserID).Count(&total).Error
// if err != nil {
// return nil, 0, utils.Wrap(err, "")
// }
// err = utils.Wrap(
// f.db(ctx).
// Where("from_user_id = ? ", fromUserID).
// Limit(int(showNumber)).
// Offset(int(pageNumber-1)*int(showNumber)).
// Find(&friendRequests).
// Error,
// "",
// )
// return
// }
// func (f *FriendRequestGorm) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) {
// err = utils.Wrap(
// f.db(ctx).
// Where("(from_user_id = ? AND to_user_id = ?) OR (from_user_id = ? AND to_user_id = ?)", fromUserID, toUserID, toUserID, fromUserID).
// Find(&friends).
// Error,
// "",
// )
// return
// }

@ -1,198 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//
//import (
// "context"
//
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/protocol/constant"
// "github.com/OpenIMSDK/tools/ormutil"
// "github.com/OpenIMSDK/tools/utils"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//var _ relation.GroupMemberModelInterface = (*GroupMemberGorm)(nil)
//
//type GroupMemberGorm struct {
// *MetaDB
//}
//
//func NewGroupMemberDB(db *gorm.DB) relation.GroupMemberModelInterface {
// return &GroupMemberGorm{NewMetaDB(db, &relation.GroupMemberModel{})}
//}
//
//func (g *GroupMemberGorm) NewTx(tx any) relation.GroupMemberModelInterface {
// return &GroupMemberGorm{NewMetaDB(tx.(*gorm.DB), &relation.GroupMemberModel{})}
//}
//
//func (g *GroupMemberGorm) Create(ctx context.Context, groupMemberList []*relation.GroupMemberModel) (err error) {
// return utils.Wrap(g.db(ctx).Create(&groupMemberList).Error, "")
//}
//
//func (g *GroupMemberGorm) Delete(ctx context.Context, groupID string, userIDs []string) (err error) {
// return utils.Wrap(
// g.db(ctx).Where("group_id = ? and user_id in (?)", groupID, userIDs).Delete(&relation.GroupMemberModel{}).Error,
// "",
// )
//}
//
//func (g *GroupMemberGorm) DeleteGroup(ctx context.Context, groupIDs []string) (err error) {
// return utils.Wrap(g.db(ctx).Where("group_id in (?)", groupIDs).Delete(&relation.GroupMemberModel{}).Error, "")
//}
//
//func (g *GroupMemberGorm) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) {
// return utils.Wrap(g.db(ctx).Where("group_id = ? and user_id = ?", groupID, userID).Updates(data).Error, "")
//}
//
//func (g *GroupMemberGorm) UpdateRoleLevel(
// ctx context.Context,
// groupID string,
// userID string,
// roleLevel int32,
//) (rowsAffected int64, err error) {
// db := g.db(ctx).Where("group_id = ? and user_id = ?", groupID, userID).Updates(map[string]any{
// "role_level": roleLevel,
// })
// return db.RowsAffected, utils.Wrap(db.Error, "")
//}
//
//func (g *GroupMemberGorm) Find(
// ctx context.Context,
// groupIDs []string,
// userIDs []string,
// roleLevels []int32,
//) (groupMembers []*relation.GroupMemberModel, err error) {
// db := g.db(ctx)
// if len(groupIDs) > 0 {
// db = db.Where("group_id in (?)", groupIDs)
// }
// if len(userIDs) > 0 {
// db = db.Where("user_id in (?)", userIDs)
// }
// if len(roleLevels) > 0 {
// db = db.Where("role_level in (?)", roleLevels)
// }
// return groupMembers, utils.Wrap(db.Find(&groupMembers).Error, "")
//}
//
//func (g *GroupMemberGorm) Take(
// ctx context.Context,
// groupID string,
// userID string,
//) (groupMember *relation.GroupMemberModel, err error) {
// groupMember = &relation.GroupMemberModel{}
// return groupMember, utils.Wrap(
// g.db(ctx).Where("group_id = ? and user_id = ?", groupID, userID).Take(groupMember).Error,
// "",
// )
//}
//
//func (g *GroupMemberGorm) TakeOwner(
// ctx context.Context,
// groupID string,
//) (groupMember *relation.GroupMemberModel, err error) {
// groupMember = &relation.GroupMemberModel{}
// return groupMember, utils.Wrap(
// g.db(ctx).Where("group_id = ? and role_level = ?", groupID, constant.GroupOwner).Take(groupMember).Error,
// "",
// )
//}
//
//func (g *GroupMemberGorm) SearchMember(
// ctx context.Context,
// keyword string,
// groupIDs []string,
// userIDs []string,
// roleLevels []int32,
// pageNumber, showNumber int32,
//) (total uint32, groupList []*relation.GroupMemberModel, err error) {
// db := g.db(ctx)
// ormutil.GormIn(&db, "group_id", groupIDs)
// ormutil.GormIn(&db, "user_id", userIDs)
// ormutil.GormIn(&db, "role_level", roleLevels)
// return ormutil.GormSearch[relation.GroupMemberModel](db, []string{"nickname"}, keyword, pageNumber, showNumber)
//}
//
//func (g *GroupMemberGorm) MapGroupMemberNum(
// ctx context.Context,
// groupIDs []string,
//) (count map[string]uint32, err error) {
// return ormutil.MapCount(g.db(ctx).Where("group_id in (?)", groupIDs), "group_id")
//}
//
//func (g *GroupMemberGorm) FindJoinUserID(
// ctx context.Context,
// groupIDs []string,
//) (groupUsers map[string][]string, err error) {
// var groupMembers []*relation.GroupMemberModel
// if err := g.db(ctx).Select("group_id, user_id").Where("group_id in (?)", groupIDs).Find(&groupMembers).Error; err != nil {
// return nil, utils.Wrap(err, "")
// }
// groupUsers = make(map[string][]string)
// for _, item := range groupMembers {
// v, ok := groupUsers[item.GroupID]
// if !ok {
// groupUsers[item.GroupID] = []string{item.UserID}
// } else {
// groupUsers[item.GroupID] = append(v, item.UserID)
// }
// }
// return groupUsers, nil
//}
//
//func (g *GroupMemberGorm) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) {
// return userIDs, utils.Wrap(g.db(ctx).Where("group_id = ?", groupID).Pluck("user_id", &userIDs).Error, "")
//}
//
//func (g *GroupMemberGorm) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
// return groupIDs, utils.Wrap(g.db(ctx).Where("user_id = ?", userID).Pluck("group_id", &groupIDs).Error, "")
//}
//
//func (g *GroupMemberGorm) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) {
// return count, utils.Wrap(g.db(ctx).Where("group_id = ?", groupID).Count(&count).Error, "")
//}
//
//func (g *GroupMemberGorm) FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) {
// var groupMembers []*relation.GroupMemberModel
// err := g.db(ctx).Select("group_id, user_id").Where("user_id IN (?)", userIDs).Find(&groupMembers).Error
// if err != nil {
// return nil, err
// }
// result := make(map[string][]string)
// for _, groupMember := range groupMembers {
// v, ok := result[groupMember.UserID]
// if !ok {
// result[groupMember.UserID] = []string{groupMember.GroupID}
// } else {
// result[groupMember.UserID] = append(v, groupMember.GroupID)
// }
// }
// return result, nil
//}
//
//func (g *GroupMemberGorm) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
// return groupIDs, utils.Wrap(
// g.db(ctx).
// Model(&relation.GroupMemberModel{}).
// Where("user_id = ? and (role_level = ? or role_level = ?)", userID, constant.GroupOwner, constant.GroupAdmin).
// Pluck("group_id", &groupIDs).
// Error,
// "",
// )
//}

@ -1,106 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//import (
// "context"
// "time"
//
// "github.com/OpenIMSDK/protocol/constant"
//
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/tools/errs"
// "github.com/OpenIMSDK/tools/ormutil"
// "github.com/OpenIMSDK/tools/utils"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//var _ relation.GroupModelInterface = (*GroupGorm)(nil)
//
//type GroupGorm struct {
// *MetaDB
//}
//
//func NewGroupDB(db *gorm.DB) relation.GroupModelInterface {
// return &GroupGorm{NewMetaDB(db, &relation.GroupModel{})}
//}
//
//func (g *GroupGorm) NewTx(tx any) relation.GroupModelInterface {
// return &GroupGorm{NewMetaDB(tx.(*gorm.DB), &relation.GroupModel{})}
//}
//
//func (g *GroupGorm) Create(ctx context.Context, groups []*relation.GroupModel) (err error) {
// return utils.Wrap(g.DB.Create(&groups).Error, "")
//}
//
//func (g *GroupGorm) UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) {
// return utils.Wrap(g.DB.Where("group_id = ?", groupID).Model(&relation.GroupModel{}).Updates(args).Error, "")
//}
//
//func (g *GroupGorm) UpdateStatus(ctx context.Context, groupID string, status int32) (err error) {
// return utils.Wrap(g.DB.Where("group_id = ?", groupID).Model(&relation.GroupModel{}).Updates(map[string]any{"status": status}).Error, "")
//}
//
//func (g *GroupGorm) Find(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) {
// return groups, utils.Wrap(g.DB.Where("group_id in (?)", groupIDs).Find(&groups).Error, "")
//}
//
//func (g *GroupGorm) Take(ctx context.Context, groupID string) (group *relation.GroupModel, err error) {
// group = &relation.GroupModel{}
// return group, utils.Wrap(g.DB.Where("group_id = ?", groupID).Take(group).Error, "")
//}
//
//func (g *GroupGorm) Search(ctx context.Context, keyword string, pageNumber, showNumber int32) (total uint32, groups []*relation.GroupModel, err error) {
// db := g.DB
// db = db.WithContext(ctx).Where("status!=?", constant.GroupStatusDismissed)
// return ormutil.GormSearch[relation.GroupModel](db, []string{"name"}, keyword, pageNumber, showNumber)
//}
//
//func (g *GroupGorm) GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) {
// return groupIDs, utils.Wrap(g.DB.Model(&relation.GroupModel{}).Where("group_type = ? ", groupType).Pluck("group_id", &groupIDs).Error, "")
//}
//
//func (g *GroupGorm) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) {
// db := g.db(ctx).Model(&relation.GroupModel{})
// if before != nil {
// db = db.Where("create_time < ?", before)
// }
// if err := db.Count(&count).Error; err != nil {
// return 0, err
// }
// return count, nil
//}
//
//func (g *GroupGorm) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) {
// var res []struct {
// Date time.Time `gorm:"column:date"`
// Count int64 `gorm:"column:count"`
// }
// err := g.db(ctx).Model(&relation.GroupModel{}).Select("DATE(create_time) AS date, count(1) AS count").Where("create_time >= ? and create_time < ?", start, end).Group("date").Find(&res).Error
// if err != nil {
// return nil, errs.Wrap(err)
// }
// v := make(map[string]int64)
// for _, r := range res {
// v[r.Date.Format("2006-01-02")] = r.Count
// }
// return v, nil
//}
//
//func (g *GroupGorm) FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) {
// return groups, utils.Wrap(g.DB.Where("group_id in (?) and status != ?", groupIDs, constant.GroupStatusDismissed).Find(&groups).Error, "")
//}

@ -1,119 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//
//import (
// "context"
//
// "github.com/OpenIMSDK/tools/ormutil"
//
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/tools/utils"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//type GroupRequestGorm struct {
// *MetaDB
//}
//
//func NewGroupRequest(db *gorm.DB) relation.GroupRequestModelInterface {
// return &GroupRequestGorm{
// NewMetaDB(db, &relation.GroupRequestModel{}),
// }
//}
//
//func (g *GroupRequestGorm) NewTx(tx any) relation.GroupRequestModelInterface {
// return &GroupRequestGorm{NewMetaDB(tx.(*gorm.DB), &relation.GroupRequestModel{})}
//}
//
//func (g *GroupRequestGorm) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) {
// return utils.Wrap(g.DB.WithContext(ctx).Create(&groupRequests).Error, utils.GetSelfFuncName())
//}
//
//func (g *GroupRequestGorm) Delete(ctx context.Context, groupID string, userID string) (err error) {
// return utils.Wrap(
// g.DB.WithContext(ctx).
// Where("group_id = ? and user_id = ? ", groupID, userID).
// Delete(&relation.GroupRequestModel{}).
// Error,
// utils.GetSelfFuncName(),
// )
//}
//
//func (g *GroupRequestGorm) UpdateHandler(
// ctx context.Context,
// groupID string,
// userID string,
// handledMsg string,
// handleResult int32,
//) (err error) {
// return utils.Wrap(
// g.DB.WithContext(ctx).
// Model(&relation.GroupRequestModel{}).
// Where("group_id = ? and user_id = ? ", groupID, userID).
// Updates(map[string]any{
// "handle_msg": handledMsg,
// "handle_result": handleResult,
// }).
// Error,
// utils.GetSelfFuncName(),
// )
//}
//
//func (g *GroupRequestGorm) Take(
// ctx context.Context,
// groupID string,
// userID string,
//) (groupRequest *relation.GroupRequestModel, err error) {
// groupRequest = &relation.GroupRequestModel{}
// return groupRequest, utils.Wrap(
// g.DB.WithContext(ctx).Where("group_id = ? and user_id = ? ", groupID, userID).Take(groupRequest).Error,
// utils.GetSelfFuncName(),
// )
//}
//
//func (g *GroupRequestGorm) Page(
// ctx context.Context,
// userID string,
// pageNumber, showNumber int32,
//) (total uint32, groups []*relation.GroupRequestModel, err error) {
// return ormutil.GormSearch[relation.GroupRequestModel](
// g.DB.WithContext(ctx).Where("user_id = ?", userID),
// nil,
// "",
// pageNumber,
// showNumber,
// )
//}
//
//func (g *GroupRequestGorm) PageGroup(
// ctx context.Context,
// groupIDs []string,
// pageNumber, showNumber int32,
//) (total uint32, groups []*relation.GroupRequestModel, err error) {
// return ormutil.GormPage[relation.GroupRequestModel](
// g.DB.WithContext(ctx).Where("group_id in ?", groupIDs),
// pageNumber,
// showNumber,
// )
//}
//
//func (g *GroupRequestGorm) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (total int64, groupRequests []*relation.GroupRequestModel, err error) {
// err = g.DB.WithContext(ctx).Where("group_id = ? and user_id in ?", groupID, userIDs).Find(&groupRequests).Error
// return int64(len(groupRequests)), groupRequests, utils.Wrap(err, utils.GetSelfFuncName())
//}

@ -1,49 +0,0 @@
package relation
//import (
// "context"
// "time"
//
// "github.com/OpenIMSDK/tools/errs"
// "github.com/OpenIMSDK/tools/ormutil"
// "gorm.io/gorm"
//
// relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//type LogGorm struct {
// db *gorm.DB
//}
//
//func (l *LogGorm) Create(ctx context.Context, log []*relationtb.Log) error {
// return errs.Wrap(l.db.WithContext(ctx).Create(log).Error)
//}
//
//func (l *LogGorm) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*relationtb.Log, error) {
// db := l.db.WithContext(ctx).Where("create_time >= ?", start)
// if end.UnixMilli() != 0 {
// db = l.db.WithContext(ctx).Where("create_time <= ?", end)
// }
// db = db.Order("create_time desc")
// return ormutil.GormSearch[relationtb.Log](db, []string{"user_id"}, keyword, pageNumber, showNumber)
//}
//
//func (l *LogGorm) Delete(ctx context.Context, logIDs []string, userID string) error {
// if userID == "" {
// return errs.Wrap(l.db.WithContext(ctx).Where("log_id in ?", logIDs).Delete(&relationtb.Log{}).Error)
// }
// return errs.Wrap(l.db.WithContext(ctx).Where("log_id in ? and user_id=?", logIDs, userID).Delete(&relationtb.Log{}).Error)
//}
//
//func (l *LogGorm) Get(ctx context.Context, logIDs []string, userID string) ([]*relationtb.Log, error) {
// var logs []*relationtb.Log
// if userID == "" {
// return logs, errs.Wrap(l.db.WithContext(ctx).Where("log_id in ?", logIDs).Find(&logs).Error)
// }
// return logs, errs.Wrap(l.db.WithContext(ctx).Where("log_id in ? and user_id=?", logIDs, userID).Find(&logs).Error)
//}
//
//func NewLogGorm(db *gorm.DB) relationtb.LogInterface {
// db.AutoMigrate(&relationtb.Log{})
// return &LogGorm{db: db}
//}

@ -1,38 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"context"
"gorm.io/gorm"
)
type MetaDB struct {
DB *gorm.DB
table any
}
func NewMetaDB(db *gorm.DB, table any) *MetaDB {
return &MetaDB{
DB: db,
table: table,
}
}
func (g *MetaDB) db(ctx context.Context) *gorm.DB {
db := g.DB.WithContext(ctx).Model(g.table)
return db
}

@ -1,157 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"fmt"
"time"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mw/specialerror"
mysqldriver "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
)
const (
maxRetry = 100 // number of retries
)
type option struct {
Username string
Password string
Address []string
Database string
LogLevel int
SlowThreshold int
MaxLifeTime int
MaxOpenConn int
MaxIdleConn int
Connect func(dsn string, maxRetry int) (*gorm.DB, error)
}
// newMysqlGormDB Initialize the database connection.
func newMysqlGormDB(o *option) (*gorm.DB, error) {
err := maybeCreateTable(o)
if err != nil {
return nil, err
}
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
o.Username, o.Password, o.Address[0], o.Database)
sqlLogger := log.NewSqlLogger(
logger.LogLevel(o.LogLevel),
true,
time.Duration(o.SlowThreshold)*time.Millisecond,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: sqlLogger,
})
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetConnMaxLifetime(time.Second * time.Duration(o.MaxLifeTime))
sqlDB.SetMaxOpenConns(o.MaxOpenConn)
sqlDB.SetMaxIdleConns(o.MaxIdleConn)
return db, nil
}
// maybeCreateTable creates a database if it does not exists.
func maybeCreateTable(o *option) error {
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
o.Username, o.Password, o.Address[0], "mysql")
var db *gorm.DB
var err error
if f := o.Connect; f != nil {
db, err = f(dsn, maxRetry)
} else {
db, err = connectToDatabase(dsn, maxRetry)
}
if err != nil {
panic(err.Error() + " Open failed " + dsn)
}
sqlDB, err := db.DB()
if err != nil {
return err
}
defer sqlDB.Close()
sql := fmt.Sprintf(
"CREATE DATABASE IF NOT EXISTS `%s` default charset utf8mb4 COLLATE utf8mb4_unicode_ci",
o.Database,
)
err = db.Exec(sql).Error
if err != nil {
return fmt.Errorf("init db %w", err)
}
return nil
}
// connectToDatabase Connection retry for mysql.
func connectToDatabase(dsn string, maxRetry int) (*gorm.DB, error) {
var db *gorm.DB
var err error
for i := 0; i <= maxRetry; i++ {
db, err = gorm.Open(mysql.Open(dsn), nil)
if err == nil {
return db, nil
}
if mysqlErr, ok := err.(*mysqldriver.MySQLError); ok && mysqlErr.Number == 1045 {
return nil, err
}
time.Sleep(time.Duration(1) * time.Second)
}
return nil, err
}
// NewGormDB gorm mysql.
func NewGormDB() (*gorm.DB, error) {
specialerror.AddReplace(gorm.ErrRecordNotFound, errs.ErrRecordNotFound)
specialerror.AddErrHandler(replaceDuplicateKey)
return newMysqlGormDB(&option{
Username: config.Config.Mysql.Username,
Password: config.Config.Mysql.Password,
Address: config.Config.Mysql.Address,
Database: config.Config.Mysql.Database,
LogLevel: config.Config.Mysql.LogLevel,
SlowThreshold: config.Config.Mysql.SlowThreshold,
MaxLifeTime: config.Config.Mysql.MaxLifeTime,
MaxOpenConn: config.Config.Mysql.MaxOpenConn,
MaxIdleConn: config.Config.Mysql.MaxIdleConn,
})
}
func replaceDuplicateKey(err error) errs.CodeError {
if IsMysqlDuplicateKey(err) {
return errs.ErrDuplicateKey
}
return nil
}
func IsMysqlDuplicateKey(err error) bool {
if mysqlErr, ok := err.(*mysqldriver.MySQLError); ok {
return mysqlErr.Number == 1062
}
return false
}

@ -1,121 +0,0 @@
package relation
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"reflect"
"testing"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func TestMaybeCreateTable(t *testing.T) {
t.Run("normal", func(t *testing.T) {
err := maybeCreateTable(&option{
Username: "root",
Password: "openIM123",
Address: []string{"172.28.0.1:13306"},
Database: "openIM_v3",
LogLevel: 4,
SlowThreshold: 500,
MaxOpenConn: 1000,
MaxIdleConn: 100,
MaxLifeTime: 60,
Connect: connect(expectExec{
query: "CREATE DATABASE IF NOT EXISTS `openIM_v3` default charset utf8mb4 COLLATE utf8mb4_unicode_ci",
args: nil,
}),
})
if err != nil {
t.Fatal(err)
}
})
t.Run("im-db", func(t *testing.T) {
err := maybeCreateTable(&option{
Username: "root",
Password: "openIM123",
Address: []string{"172.28.0.1:13306"},
Database: "im-db",
LogLevel: 4,
SlowThreshold: 500,
MaxOpenConn: 1000,
MaxIdleConn: 100,
MaxLifeTime: 60,
Connect: connect(expectExec{
query: "CREATE DATABASE IF NOT EXISTS `im-db` default charset utf8mb4 COLLATE utf8mb4_unicode_ci",
args: nil,
}),
})
if err != nil {
t.Fatal(err)
}
})
t.Run("err", func(t *testing.T) {
e := errors.New("e")
err := maybeCreateTable(&option{
Username: "root",
Password: "openIM123",
Address: []string{"172.28.0.1:13306"},
Database: "openIM_v3",
LogLevel: 4,
SlowThreshold: 500,
MaxOpenConn: 1000,
MaxIdleConn: 100,
MaxLifeTime: 60,
Connect: connect(expectExec{
err: e,
}),
})
if !errors.Is(err, e) {
t.Fatalf("err not is e: %v", err)
}
})
}
func connect(e expectExec) func(string, int) (*gorm.DB, error) {
return func(string, int) (*gorm.DB, error) {
return gorm.Open(mysql.New(mysql.Config{
SkipInitializeWithVersion: true,
Conn: sql.OpenDB(e),
}), &gorm.Config{
Logger: logger.Discard,
})
}
}
type expectExec struct {
err error
query string
args []driver.NamedValue
}
func (c expectExec) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
if c.err != nil {
return nil, c.err
}
if query != c.query {
return nil, fmt.Errorf("query mismatch. expect: %s, got: %s", c.query, query)
}
if reflect.DeepEqual(args, c.args) {
return nil, fmt.Errorf("args mismatch. expect: %v, got: %v", c.args, args)
}
return noEffectResult{}, nil
}
func (e expectExec) Connect(context.Context) (driver.Conn, error) { return e, nil }
func (expectExec) Driver() driver.Driver { panic("not implemented") }
func (expectExec) Prepare(query string) (driver.Stmt, error) { panic("not implemented") }
func (expectExec) Close() (e error) { return }
func (expectExec) Begin() (driver.Tx, error) { panic("not implemented") }
type noEffectResult struct{}
func (noEffectResult) LastInsertId() (i int64, e error) { return }
func (noEffectResult) RowsAffected() (i int64, e error) { return }

@ -1,54 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//
//import (
// "context"
//
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/tools/errs"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//type ObjectInfoGorm struct {
// *MetaDB
//}
//
//func NewObjectInfo(db *gorm.DB) relation.ObjectInfoModelInterface {
// return &ObjectInfoGorm{
// NewMetaDB(db, &relation.ObjectModel{}),
// }
//}
//
//func (o *ObjectInfoGorm) NewTx(tx any) relation.ObjectInfoModelInterface {
// return &ObjectInfoGorm{
// NewMetaDB(tx.(*gorm.DB), &relation.ObjectModel{}),
// }
//}
//
//func (o *ObjectInfoGorm) SetObject(ctx context.Context, obj *relation.ObjectModel) (err error) {
// if err := o.DB.WithContext(ctx).Where("name = ?", obj.Name).FirstOrCreate(obj).Error; err != nil {
// return errs.Wrap(err)
// }
// return nil
//}
//
//func (o *ObjectInfoGorm) Take(ctx context.Context, name string) (info *relation.ObjectModel, err error) {
// info = &relation.ObjectModel{}
// return info, errs.Wrap(o.DB.WithContext(ctx).Where("name = ?", name).Take(info).Error)
//}

@ -1,138 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
//
//import (
// "context"
// "time"
//
// "github.com/OpenIMSDK/tools/errs"
//
// "gorm.io/gorm"
//
// "github.com/OpenIMSDK/tools/utils"
//
// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
//)
//
//type UserGorm struct {
// *MetaDB
//}
//
//func NewUserGorm(db *gorm.DB) relation.UserModelInterface {
// //return &UserGorm{NewMetaDB(db, &relation.UserModel{})}
// return nil
//}
//
//// 插入多条.
//func (u *UserGorm) Create(ctx context.Context, users []*relation.UserModel) (err error) {
// return utils.Wrap(u.db(ctx).Create(&users).Error, "")
//}
//
//// 更新用户信息 零值.
//func (u *UserGorm) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) {
// return utils.Wrap(u.db(ctx).Model(&relation.UserModel{}).Where("user_id = ?", userID).Updates(args).Error, "")
//}
//
//// 更新多个用户信息 非零值.
//func (u *UserGorm) Update(ctx context.Context, user *relation.UserModel) (err error) {
// return utils.Wrap(u.db(ctx).Model(user).Updates(user).Error, "")
//}
//
//// 获取指定用户信息 不存在,也不返回错误.
//func (u *UserGorm) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
// err = utils.Wrap(u.db(ctx).Where("user_id in (?)", userIDs).Find(&users).Error, "")
// return users, err
//}
//
//// 获取某个用户信息 不存在,则返回错误.
//func (u *UserGorm) Take(ctx context.Context, userID string) (user *relation.UserModel, err error) {
// user = &relation.UserModel{}
// err = utils.Wrap(u.db(ctx).Where("user_id = ?", userID).Take(&user).Error, "")
// return user, err
//}
//
//// 获取用户信息 不存在,不返回错误.
//func (u *UserGorm) Page(
// ctx context.Context,
// pageNumber, showNumber int32,
//) (users []*relation.UserModel, count int64, err error) {
// err = utils.Wrap(u.db(ctx).Count(&count).Error, "")
// if err != nil {
// return
// }
// err = utils.Wrap(
// u.db(ctx).
// Limit(int(showNumber)).
// Offset(int((pageNumber-1)*showNumber)).
// Find(&users).
// Order("create_time DESC").
// Error,
// "",
// )
// return
//}
//
//// 获取所有用户ID.
//func (u *UserGorm) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) {
// if pageNumber == 0 || showNumber == 0 {
// return userIDs, errs.Wrap(u.db(ctx).Pluck("user_id", &userIDs).Error)
// } else {
// return userIDs, errs.Wrap(u.db(ctx).Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("user_id", &userIDs).Error)
// }
//}
//
//func (u *UserGorm) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
// err = u.db(ctx).Model(&relation.UserModel{}).Where("user_id = ?", userID).Pluck("global_recv_msg_opt", &opt).Error
// return opt, err
//}
//
//func (u *UserGorm) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) {
// db := u.db(ctx).Model(&relation.UserModel{})
// if before != nil {
// db = db.Where("create_time < ?", before)
// }
// if err := db.Count(&count).Error; err != nil {
// return 0, err
// }
// return count, nil
//}
//
//func (u *UserGorm) CountRangeEverydayTotal(
// ctx context.Context,
// start time.Time,
// end time.Time,
//) (map[string]int64, error) {
// var res []struct {
// Date time.Time `gorm:"column:date"`
// Count int64 `gorm:"column:count"`
// }
// err := u.db(ctx).
// Model(&relation.UserModel{}).
// Select("DATE(create_time) AS date, count(1) AS count").
// Where("create_time >= ? and create_time < ?", start, end).
// Group("date").
// Find(&res).
// Error
// if err != nil {
// return nil, errs.Wrap(err)
// }
// v := make(map[string]int64)
// for _, r := range res {
// v[r.Date.Format("2006-01-02")] = r.Count
// }
// return v, nil
//}

@ -1,323 +0,0 @@
package kodo
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
awss3config "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
awss3 "github.com/aws/aws-sdk-go-v2/service/s3"
awss3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/qiniu/go-sdk/v7/auth"
"github.com/qiniu/go-sdk/v7/storage"
)
const (
minPartSize = 1024 * 1024 * 1 // 1MB
maxPartSize = 1024 * 1024 * 1024 * 5 // 5GB
maxNumSize = 10000
)
type Kodo struct {
AccessKey string
SecretKey string
Region string
Token string
Endpoint string
BucketURL string
Auth *auth.Credentials
Client *awss3.Client
PresignClient *awss3.PresignClient
}
func NewKodo() (s3.Interface, error) {
conf := config.Config.Object.Kodo
//init client
cfg, err := awss3config.LoadDefaultConfig(context.TODO(),
awss3config.WithRegion(conf.Bucket),
awss3config.WithEndpointResolverWithOptions(
aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{URL: conf.Endpoint}, nil
})),
awss3config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
conf.AccessKeyID,
conf.AccessKeySecret,
conf.SessionToken),
),
)
if err != nil {
panic(err)
}
client := awss3.NewFromConfig(cfg)
presignClient := awss3.NewPresignClient(client)
return &Kodo{
AccessKey: conf.AccessKeyID,
SecretKey: conf.AccessKeySecret,
Region: conf.Bucket,
BucketURL: conf.BucketURL,
Auth: auth.New(conf.AccessKeyID, conf.AccessKeySecret),
Client: client,
PresignClient: presignClient,
}, nil
}
func (k Kodo) Engine() string {
return "kodo"
}
func (k Kodo) PartLimit() *s3.PartLimit {
return &s3.PartLimit{
MinPartSize: minPartSize,
MaxPartSize: maxPartSize,
MaxNumSize: maxNumSize,
}
}
func (k Kodo) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) {
result, err := k.Client.CreateMultipartUpload(ctx, &awss3.CreateMultipartUploadInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
})
if err != nil {
return nil, err
}
return &s3.InitiateMultipartUploadResult{
UploadID: aws.ToString(result.UploadId),
Bucket: aws.ToString(result.Bucket),
Key: aws.ToString(result.Key),
}, nil
}
func (k Kodo) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) {
kodoParts := make([]awss3types.CompletedPart, len(parts))
for i, part := range parts {
kodoParts[i] = awss3types.CompletedPart{
PartNumber: aws.Int32(int32(part.PartNumber)),
ETag: aws.String(part.ETag),
}
}
result, err := k.Client.CompleteMultipartUpload(ctx, &awss3.CompleteMultipartUploadInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
UploadId: aws.String(uploadID),
MultipartUpload: &awss3types.CompletedMultipartUpload{Parts: kodoParts},
})
if err != nil {
return nil, err
}
return &s3.CompleteMultipartUploadResult{
Location: aws.ToString(result.Location),
Bucket: aws.ToString(result.Bucket),
Key: aws.ToString(result.Key),
ETag: strings.ToLower(strings.ReplaceAll(aws.ToString(result.ETag), `"`, ``)),
}, nil
}
func (k Kodo) PartSize(ctx context.Context, size int64) (int64, error) {
if size <= 0 {
return 0, errors.New("size must be greater than 0")
}
if size > maxPartSize*maxNumSize {
return 0, fmt.Errorf("size must be less than %db", maxPartSize*maxNumSize)
}
if size <= minPartSize*maxNumSize {
return minPartSize, nil
}
partSize := size / maxNumSize
if size%maxNumSize != 0 {
partSize++
}
return partSize, nil
}
func (k Kodo) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) {
result := s3.AuthSignResult{
URL: k.BucketURL + "/" + name,
Query: url.Values{"uploadId": {uploadID}},
Header: make(http.Header),
Parts: make([]s3.SignPart, len(partNumbers)),
}
for i, partNumber := range partNumbers {
part, _ := k.PresignClient.PresignUploadPart(ctx, &awss3.UploadPartInput{
Bucket: aws.String(k.Region),
UploadId: aws.String(uploadID),
Key: aws.String(name),
PartNumber: aws.Int32(int32(partNumber)),
})
result.Parts[i] = s3.SignPart{
PartNumber: partNumber,
URL: part.URL,
Header: part.SignedHeader,
}
}
return &result, nil
}
func (k Kodo) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) {
object, err := k.PresignClient.PresignPutObject(ctx, &awss3.PutObjectInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
}, func(po *awss3.PresignOptions) {
po.Expires = expire
})
return object.URL, err
}
func (k Kodo) DeleteObject(ctx context.Context, name string) error {
_, err := k.Client.DeleteObject(ctx, &awss3.DeleteObjectInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
})
return err
}
func (k Kodo) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) {
result, err := k.Client.CopyObject(ctx, &awss3.CopyObjectInput{
Bucket: aws.String(k.Region),
CopySource: aws.String(k.Region + "/" + src),
Key: aws.String(dst),
})
if err != nil {
return nil, err
}
return &s3.CopyObjectInfo{
Key: dst,
ETag: strings.ToLower(strings.ReplaceAll(aws.ToString(result.CopyObjectResult.ETag), `"`, ``)),
}, nil
}
func (k Kodo) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) {
info, err := k.Client.HeadObject(ctx, &awss3.HeadObjectInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
})
if err != nil {
return nil, err
}
res := &s3.ObjectInfo{Key: name}
res.Size = aws.ToInt64(info.ContentLength)
res.ETag = strings.ToLower(strings.ReplaceAll(aws.ToString(info.ETag), `"`, ``))
return res, nil
}
func (k Kodo) IsNotFound(err error) bool {
return true
}
func (k Kodo) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error {
_, err := k.Client.AbortMultipartUpload(ctx, &awss3.AbortMultipartUploadInput{
UploadId: aws.String(uploadID),
Bucket: aws.String(k.Region),
Key: aws.String(name),
})
return err
}
func (k Kodo) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) {
result, err := k.Client.ListParts(ctx, &awss3.ListPartsInput{
Key: aws.String(name),
UploadId: aws.String(uploadID),
Bucket: aws.String(k.Region),
MaxParts: aws.Int32(int32(maxParts)),
PartNumberMarker: aws.String(strconv.Itoa(partNumberMarker)),
})
if err != nil {
return nil, err
}
res := &s3.ListUploadedPartsResult{
Key: aws.ToString(result.Key),
UploadID: aws.ToString(result.UploadId),
MaxParts: int(aws.ToInt32(result.MaxParts)),
UploadedParts: make([]s3.UploadedPart, len(result.Parts)),
}
// int to string
NextPartNumberMarker, err := strconv.Atoi(aws.ToString(result.NextPartNumberMarker))
if err != nil {
return nil, err
}
res.NextPartNumberMarker = NextPartNumberMarker
for i, part := range result.Parts {
res.UploadedParts[i] = s3.UploadedPart{
PartNumber: int(aws.ToInt32(part.PartNumber)),
LastModified: aws.ToTime(part.LastModified),
ETag: aws.ToString(part.ETag),
Size: aws.ToInt64(part.Size),
}
}
return res, nil
}
func (k Kodo) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
//get object head
info, err := k.Client.HeadObject(ctx, &awss3.HeadObjectInput{
Bucket: aws.String(k.Region),
Key: aws.String(name),
})
if err != nil {
return "", errors.New("AccessURL object not found")
}
if opt != nil {
if opt.ContentType != aws.ToString(info.ContentType) {
//修改文件类型
err := k.SetObjectContentType(ctx, name, opt.ContentType)
if err != nil {
return "", errors.New("AccessURL setContentType error")
}
}
}
imageMogr := ""
//image dispose
if opt != nil {
if opt.Image != nil {
//https://developer.qiniu.com/dora/8255/the-zoom
process := ""
if opt.Image.Width > 0 {
process += strconv.Itoa(opt.Image.Width) + "x"
}
if opt.Image.Height > 0 {
if opt.Image.Width > 0 {
process += strconv.Itoa(opt.Image.Height)
} else {
process += "x" + strconv.Itoa(opt.Image.Height)
}
}
imageMogr = "imageMogr2/thumbnail/" + process
}
}
//expire
deadline := time.Now().Add(time.Second * expire).Unix()
domain := k.BucketURL
query := url.Values{}
if opt != nil && opt.Filename != "" {
query.Add("attname", opt.Filename)
}
privateURL := storage.MakePrivateURLv2WithQuery(k.Auth, domain, name, query, deadline)
if imageMogr != "" {
privateURL += "&" + imageMogr
}
return privateURL, nil
}
func (k *Kodo) SetObjectContentType(ctx context.Context, name string, contentType string) error {
//set object content-type
_, err := k.Client.CopyObject(ctx, &awss3.CopyObjectInput{
Bucket: aws.String(k.Region),
CopySource: aws.String(k.Region + "/" + name),
Key: aws.String(name),
ContentType: aws.String(contentType),
MetadataDirective: awss3types.MetadataDirectiveReplace,
})
return err
}

@ -17,33 +17,27 @@ package relation
import ( import (
"context" "context"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
BlackModelTableName = "blacks"
) )
type BlackModel struct { type BlackModel struct {
OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` OwnerUserID string `bson:"owner_user_id"`
BlockUserID string `gorm:"column:block_user_id;primary_key;size:64"` BlockUserID string `bson:"block_user_id"`
CreateTime time.Time `gorm:"column:create_time"` CreateTime time.Time `bson:"create_time"`
AddSource int32 `gorm:"column:add_source"` AddSource int32 `bson:"add_source"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"` OperatorUserID string `bson:"operator_user_id"`
Ex string `gorm:"column:ex;size:1024"` Ex string `bson:"ex"`
}
func (BlackModel) TableName() string {
return BlackModelTableName
} }
type BlackModelInterface interface { type BlackModelInterface interface {
Create(ctx context.Context, blacks []*BlackModel) (err error) Create(ctx context.Context, blacks []*BlackModel) (err error)
Delete(ctx context.Context, blacks []*BlackModel) (err error) Delete(ctx context.Context, blacks []*BlackModel) (err error)
UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) //UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error)
Update(ctx context.Context, blacks []*BlackModel) (err error) //Update(ctx context.Context, blacks []*BlackModel) (err error)
Find(ctx context.Context, blacks []*BlackModel) (blackList []*BlackModel, err error) Find(ctx context.Context, blacks []*BlackModel) (blackList []*BlackModel, err error)
Take(ctx context.Context, ownerUserID, blockUserID string) (black *BlackModel, err error) Take(ctx context.Context, ownerUserID, blockUserID string) (black *BlackModel, err error)
FindOwnerBlacks(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (blacks []*BlackModel, total int64, err error) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*BlackModel, err error)
FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*BlackModel, err error) FindOwnerBlackInfos(ctx context.Context, ownerUserID string, userIDs []string) (blacks []*BlackModel, err error)
FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error)
} }

@ -1,51 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation
import (
"time"
pbmsg "github.com/OpenIMSDK/protocol/msg"
)
const (
ChatLogModelTableName = "chat_logs"
)
type ChatLogModel struct {
ServerMsgID string `gorm:"column:server_msg_id;primary_key;type:char(64)" json:"serverMsgID"`
ClientMsgID string `gorm:"column:client_msg_id;type:char(64)" json:"clientMsgID"`
SendID string `gorm:"column:send_id;type:char(64);index:send_id,priority:2" json:"sendID"`
RecvID string `gorm:"column:recv_id;type:char(64);index:recv_id,priority:2" json:"recvID"`
SenderPlatformID int32 `gorm:"column:sender_platform_id" json:"senderPlatformID"`
SenderNickname string `gorm:"column:sender_nick_name;type:varchar(255)" json:"senderNickname"`
SenderFaceURL string `gorm:"column:sender_face_url;type:varchar(255);" json:"senderFaceURL"`
SessionType int32 `gorm:"column:session_type;index:session_type,priority:2;index:session_type_alone" json:"sessionType"`
MsgFrom int32 `gorm:"column:msg_from" json:"msgFrom"`
ContentType int32 `gorm:"column:content_type;index:content_type,priority:2;index:content_type_alone" json:"contentType"`
Content string `gorm:"column:content;type:varchar(3000)" json:"content"`
Status int32 `gorm:"column:status" json:"status"`
SendTime time.Time `gorm:"column:send_time;index:sendTime;index:content_type,priority:1;index:session_type,priority:1;index:recv_id,priority:1;index:send_id,priority:1" json:"sendTime"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
}
func (ChatLogModel) TableName() string {
return ChatLogModelTableName
}
type ChatLogModelInterface interface {
Create(msg *pbmsg.MsgDataToMQ) error
}

@ -16,35 +16,11 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
conversationModelTableName = "conversations"
) )
//type ConversationModel struct {
// OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"`
// ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"`
// ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"`
// UserID string `gorm:"column:user_id;type:char(64)" json:"userID"`
// GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"`
// RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"`
// IsPinned bool `gorm:"column:is_pinned" json:"isPinned"`
// IsPrivateChat bool `gorm:"column:is_private_chat" json:"isPrivateChat"`
// BurnDuration int32 `gorm:"column:burn_duration;default:30" json:"burnDuration"`
// GroupAtType int32 `gorm:"column:group_at_type" json:"groupAtType"`
// AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"`
// Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
// MaxSeq int64 `gorm:"column:max_seq" json:"maxSeq"`
// MinSeq int64 `gorm:"column:min_seq" json:"minSeq"`
// CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"`
// IsMsgDestruct bool `gorm:"column:is_msg_destruct;default:false"`
// MsgDestructTime int64 `gorm:"column:msg_destruct_time;default:604800"`
// LatestMsgDestructTime time.Time `gorm:"column:latest_msg_destruct_time;autoCreateTime"`
//}
type ConversationModel struct { type ConversationModel struct {
OwnerUserID string `bson:"owner_user_id"` OwnerUserID string `bson:"owner_user_id"`
ConversationID string `bson:"conversation_id"` ConversationID string `bson:"conversation_id"`
@ -66,10 +42,6 @@ type ConversationModel struct {
LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"` LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"`
} }
func (ConversationModel) TableName() string {
return conversationModelTableName
}
type ConversationModelInterface interface { type ConversationModelInterface interface {
Create(ctx context.Context, conversations []*ConversationModel) (err error) Create(ctx context.Context, conversations []*ConversationModel) (err error)
Delete(ctx context.Context, groupIDs []string) (err error) Delete(ctx context.Context, groupIDs []string) (err error)
@ -83,11 +55,9 @@ type ConversationModelInterface interface {
FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error) FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error)
FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error)
//FindSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
GetAllConversationIDs(ctx context.Context) ([]string, error) GetAllConversationIDs(ctx context.Context) ([]string, error)
GetAllConversationIDsNumber(ctx context.Context) (int64, error) GetAllConversationIDsNumber(ctx context.Context) (int64, error)
PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error)
//GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (hashReadSeqs map[string]int64, err error)
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*ConversationModel, error) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*ConversationModel, error)
GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error)
GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error)

@ -1,15 +0,0 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package relation // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"

@ -18,36 +18,18 @@ import (
"context" "context"
"time" "time"
"go.mongodb.org/mongo-driver/bson/primitive" "github.com/OpenIMSDK/tools/pagination"
) )
const (
FriendModelCollectionName = "friends"
)
// OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"`
// FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"`
// Remark string `gorm:"column:remark;size:255"`
// CreateTime time.Time `gorm:"column:create_time;autoCreateTime"`
// AddSource int32 `gorm:"column:add_source"`
// OperatorUserID string `gorm:"column:operator_user_id;size:64"`
// Ex string `gorm:"column:ex;size:1024"`
// FriendModel represents the data structure for a friend relationship in MongoDB. // FriendModel represents the data structure for a friend relationship in MongoDB.
type FriendModel struct { type FriendModel struct {
ID primitive.ObjectID `bson:"_id,omitempty"` OwnerUserID string `bson:"owner_user_id"`
OwnerUserID string `bson:"owner_user_id"` FriendUserID string `bson:"friend_user_id"`
FriendUserID string `bson:"friend_user_id"` Remark string `bson:"remark"`
Remark string `bson:"remark"` CreateTime time.Time `bson:"create_time"`
CreateTime time.Time `bson:"create_time"` AddSource int32 `bson:"add_source"`
AddSource int32 `bson:"add_source"` OperatorUserID string `bson:"operator_user_id"`
OperatorUserID string `bson:"operator_user_id"` Ex string `bson:"ex"`
Ex string `bson:"ex"`
}
// CollectionName returns the name of the MongoDB collection.
func (FriendModel) CollectionName() string {
return FriendModelCollectionName
} }
// FriendModelInterface defines the operations for managing friends in MongoDB. // FriendModelInterface defines the operations for managing friends in MongoDB.
@ -58,9 +40,7 @@ type FriendModelInterface interface {
Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error)
// UpdateByMap updates specific fields of a friend document using a map. // UpdateByMap updates specific fields of a friend document using a map.
UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]any) (err error) UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]any) (err error)
// Update modifies multiple friend documents. // UpdateRemark modify remarks.
// Update(ctx context.Context, friends []*FriendModel) (err error)
// UpdateRemark updates the remark for a specific friend.
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
// Take retrieves a single friend document. Returns an error if not found. // Take retrieves a single friend document. Returns an error if not found.
Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error) Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error)
@ -71,11 +51,9 @@ type FriendModelInterface interface {
// FindReversalFriends finds users who have added the specified user as a friend. // FindReversalFriends finds users who have added the specified user as a friend.
FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*FriendModel, err error) FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*FriendModel, err error)
// FindOwnerFriends retrieves a paginated list of friends for a given owner. // FindOwnerFriends retrieves a paginated list of friends for a given owner.
FindOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (friends []*FriendModel, total int64, err error) FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error)
// FindInWhoseFriends finds users who have added the specified user as a friend, with pagination. // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination.
FindInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) (friends []*FriendModel, total int64, err error) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error)
// FindFriendUserIDs retrieves a list of friend user IDs for a given owner. // FindFriendUserIDs retrieves a list of friend user IDs for a given owner.
FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
// NewTx creates a new transaction.
NewTx(tx any) FriendModelInterface
} }

@ -18,26 +18,19 @@ import (
"context" "context"
"time" "time"
"go.mongodb.org/mongo-driver/bson/primitive" "github.com/OpenIMSDK/tools/pagination"
) )
const FriendRequestModelCollectionName = "friend_requests"
type FriendRequestModel struct { type FriendRequestModel struct {
ID primitive.ObjectID `bson:"_id,omitempty"` FromUserID string `bson:"from_user_id"`
FromUserID string `bson:"from_user_id"` ToUserID string `bson:"to_user_id"`
ToUserID string `bson:"to_user_id"` HandleResult int32 `bson:"handle_result"`
HandleResult int32 `bson:"handle_result"` ReqMsg string `bson:"req_msg"`
ReqMsg string `bson:"req_msg"` CreateTime time.Time `bson:"create_time"`
CreateTime time.Time `bson:"create_time"` HandlerUserID string `bson:"handler_user_id"`
HandlerUserID string `bson:"handler_user_id"` HandleMsg string `bson:"handle_msg"`
HandleMsg string `bson:"handle_msg"` HandleTime time.Time `bson:"handle_time"`
HandleTime time.Time `bson:"handle_time"` Ex string `bson:"ex"`
Ex string `bson:"ex"`
}
func (FriendRequestModel) CollectionName() string {
return FriendRequestModelCollectionName
} }
type FriendRequestModelInterface interface { type FriendRequestModelInterface interface {
@ -53,11 +46,8 @@ type FriendRequestModelInterface interface {
Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
// Get list of friend requests received by toUserID // Get list of friend requests received by toUserID
FindToUserID(ctx context.Context,toUserID string,pageNumber, showNumber int32,) (friendRequests []*FriendRequestModel, total int64, err error) FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error)
// Get list of friend requests sent by fromUserID // Get list of friend requests sent by fromUserID
FindFromUserID(ctx context.Context,fromUserID string,pageNumber, showNumber int32,) (friendRequests []*FriendRequestModel, total int64, err error) FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error)
FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error)
NewTx(tx any) FriendRequestModelInterface
// Check if the record exists
Exist(ctx context.Context, userID string) (exist bool, err error)
} }

@ -16,32 +16,11 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupModelTableName = "groups"
) )
//type GroupModel struct {
// GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"`
// GroupName string `gorm:"column:name;size:255" json:"groupName"`
// Notification string `gorm:"column:notification;size:255" json:"notification"`
// Introduction string `gorm:"column:introduction;size:255" json:"introduction"`
// FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"`
// CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"`
// Ex string `gorm:"column:ex" json:"ex;size:1024"`
// Status int32 `gorm:"column:status"`
// CreatorUserID string `gorm:"column:creator_user_id;size:64"`
// GroupType int32 `gorm:"column:group_type"`
// NeedVerification int32 `gorm:"column:need_verification"`
// LookMemberInfo int32 `gorm:"column:look_member_info" json:"lookMemberInfo"`
// ApplyMemberFriend int32 `gorm:"column:apply_member_friend" json:"applyMemberFriend"`
// NotificationUpdateTime time.Time `gorm:"column:notification_update_time"`
// NotificationUserID string `gorm:"column:notification_user_id;size:64"`
//}
type GroupModel struct { type GroupModel struct {
GroupID string `bson:"group_id"` GroupID string `bson:"group_id"`
GroupName string `bson:"group_name"` GroupName string `bson:"group_name"`
@ -60,10 +39,6 @@ type GroupModel struct {
NotificationUserID string `bson:"notification_user_id"` NotificationUserID string `bson:"notification_user_id"`
} }
func (GroupModel) TableName() string {
return GroupModelTableName
}
type GroupModelInterface interface { type GroupModelInterface interface {
Create(ctx context.Context, groups []*GroupModel) (err error) Create(ctx context.Context, groups []*GroupModel) (err error)
UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error)

@ -16,28 +16,11 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupMemberModelTableName = "group_members"
) )
//type GroupMemberModel struct {
// GroupID string `gorm:"column:group_id;primary_key;size:64"`
// UserID string `gorm:"column:user_id;primary_key;size:64"`
// Nickname string `gorm:"column:nickname;size:255"`
// FaceURL string `gorm:"column:user_group_face_url;size:255"`
// RoleLevel int32 `gorm:"column:role_level"`
// JoinTime time.Time `gorm:"column:join_time"`
// JoinSource int32 `gorm:"column:join_source"`
// InviterUserID string `gorm:"column:inviter_user_id;size:64"`
// OperatorUserID string `gorm:"column:operator_user_id;size:64"`
// MuteEndTime time.Time `gorm:"column:mute_end_time"`
// Ex string `gorm:"column:ex;size:1024"`
//}
type GroupMemberModel struct { type GroupMemberModel struct {
GroupID string `bson:"group_id"` GroupID string `bson:"group_id"`
UserID string `bson:"user_id"` UserID string `bson:"user_id"`
@ -52,10 +35,6 @@ type GroupMemberModel struct {
Ex string `bson:"ex"` Ex string `bson:"ex"`
} }
func (GroupMemberModel) TableName() string {
return GroupMemberModelTableName
}
type GroupMemberModelInterface interface { type GroupMemberModelInterface interface {
//NewTx(tx any) GroupMemberModelInterface //NewTx(tx any) GroupMemberModelInterface
Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error)

@ -16,28 +16,11 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupRequestModelTableName = "group_requests"
) )
//type GroupRequestModel struct {
// UserID string `gorm:"column:user_id;primary_key;size:64"`
// GroupID string `gorm:"column:group_id;primary_key;size:64"`
// HandleResult int32 `gorm:"column:handle_result"`
// ReqMsg string `gorm:"column:req_msg;size:1024"`
// HandledMsg string `gorm:"column:handle_msg;size:1024"`
// ReqTime time.Time `gorm:"column:req_time"`
// HandleUserID string `gorm:"column:handle_user_id;size:64"`
// HandledTime time.Time `gorm:"column:handle_time"`
// JoinSource int32 `gorm:"column:join_source"`
// InviterUserID string `gorm:"column:inviter_user_id;size:64"`
// Ex string `gorm:"column:ex;size:1024"`
//}
type GroupRequestModel struct { type GroupRequestModel struct {
UserID string `bson:"user_id"` UserID string `bson:"user_id"`
GroupID string `bson:"group_id"` GroupID string `bson:"group_id"`
@ -52,10 +35,6 @@ type GroupRequestModel struct {
Ex string `bson:"ex"` Ex string `bson:"ex"`
} }
func (GroupRequestModel) TableName() string {
return GroupRequestModelTableName
}
type GroupRequestModelInterface interface { type GroupRequestModelInterface interface {
Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error)
Delete(ctx context.Context, groupID string, userID string) (err error) Delete(ctx context.Context, groupID string, userID string) (err error)

@ -2,23 +2,12 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
)
//type Log struct { "github.com/OpenIMSDK/tools/pagination"
// LogID string `gorm:"column:log_id;primary_key;type:char(64)"` )
// Platform string `gorm:"column:platform;type:varchar(32)"`
// UserID string `gorm:"column:user_id;type:char(64)"`
// CreateTime time.Time `gorm:"index:,sort:desc"`
// Url string `gorm:"column:url;type varchar(255)"`
// FileName string `gorm:"column:filename;type varchar(255)"`
// SystemType string `gorm:"column:system_type;type varchar(255)"`
// Version string `gorm:"column:version;type varchar(255)"`
// Ex string `gorm:"column:ex;type varchar(255)"`
//}
type Log struct { type LogModel struct {
LogID string `bson:"log_id"` LogID string `bson:"log_id"`
Platform string `bson:"platform"` Platform string `bson:"platform"`
UserID string `bson:"user_id"` UserID string `bson:"user_id"`
@ -31,8 +20,8 @@ type Log struct {
} }
type LogInterface interface { type LogInterface interface {
Create(ctx context.Context, log []*Log) error Create(ctx context.Context, log []*LogModel) error
Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*Log, error) Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*LogModel, error)
Delete(ctx context.Context, logID []string, userID string) error Delete(ctx context.Context, logID []string, userID string) error
Get(ctx context.Context, logIDs []string, userID string) ([]*Log, error) Get(ctx context.Context, logIDs []string, userID string) ([]*LogModel, error)
} }

@ -19,10 +19,6 @@ import (
"time" "time"
) )
const (
ObjectInfoModelTableName = "object"
)
type ObjectModel struct { type ObjectModel struct {
Name string `bson:"name"` Name string `bson:"name"`
UserID string `bson:"user_id"` UserID string `bson:"user_id"`
@ -35,22 +31,6 @@ type ObjectModel struct {
CreateTime time.Time `bson:"create_time"` CreateTime time.Time `bson:"create_time"`
} }
//type ObjectModel struct {
// Name string `gorm:"column:name;primary_key"`
// UserID string `gorm:"column:user_id"`
// Hash string `gorm:"column:hash"`
// Engine string `gorm:"column:engine"`
// Key string `gorm:"column:key"`
// Size int64 `gorm:"column:size"`
// ContentType string `gorm:"column:content_type"`
// Cause string `gorm:"column:cause"`
// CreateTime time.Time `gorm:"column:create_time"`
//}
func (ObjectModel) TableName() string {
return ObjectInfoModelTableName
}
type ObjectInfoModelInterface interface { type ObjectInfoModelInterface interface {
SetObject(ctx context.Context, obj *ObjectModel) error SetObject(ctx context.Context, obj *ObjectModel) error
Take(ctx context.Context, engine string, name string) (*ObjectModel, error) Take(ctx context.Context, engine string, name string) (*ObjectModel, error)

@ -16,8 +16,9 @@ package relation
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/common/pagination"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
) )
type UserModel struct { type UserModel struct {

@ -15,9 +15,8 @@
package relation package relation
import ( import (
"gorm.io/gorm"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"go.mongodb.org/mongo-driver/mongo"
) )
type BatchUpdateGroupMember struct { type BatchUpdateGroupMember struct {
@ -32,5 +31,5 @@ type GroupSimpleUserID struct {
} }
func IsNotFound(err error) bool { func IsNotFound(err error) bool {
return utils.Unwrap(err) == gorm.ErrRecordNotFound return utils.Unwrap(err) == mongo.ErrNoDocuments
} }

@ -1,19 +0,0 @@
package tx
import (
"context"
"github.com/OpenIMSDK/tools/tx"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
func NewAuto(ctx context.Context, cli *mongo.Client) (tx.CtxTx, error) {
var res map[string]any
if err := cli.Database("admin").RunCommand(ctx, bson.M{"isMaster": 1}).Decode(&res); err != nil {
return nil, err
}
if _, ok := res["setName"]; ok {
return NewMongoTx(cli), nil
}
return NewInvalidTx(), nil
}

@ -1,16 +0,0 @@
package tx
import (
"context"
"github.com/OpenIMSDK/tools/tx"
)
func NewInvalidTx() tx.CtxTx {
return invalid{}
}
type invalid struct{}
func (m invalid) Transaction(ctx context.Context, fn func(ctx context.Context) error) error {
return fn(ctx)
}

@ -1,28 +0,0 @@
package tx
import (
"context"
"github.com/OpenIMSDK/tools/tx"
"go.mongodb.org/mongo-driver/mongo"
)
func NewMongoTx(client *mongo.Client) tx.CtxTx {
return &mongoTx{
client: client,
}
}
type mongoTx struct {
client *mongo.Client
}
func (m *mongoTx) Transaction(ctx context.Context, fn func(ctx context.Context) error) error {
sess, err := m.client.StartSession()
if err != nil {
return err
}
_, err = sess.WithTransaction(ctx, func(ctx mongo.SessionContext) (interface{}, error) {
return nil, fn(ctx)
})
return err
}
Loading…
Cancel
Save