From 7a13284b2e413d26ffd04bf7828d99340bf79f66 Mon Sep 17 00:00:00 2001 From: xuexihuang <1339326187@qq.com> Date: Tue, 21 Nov 2023 17:09:31 +0800 Subject: [PATCH 01/18] kafka work error ,alertmanager work error (#1455) * Code adaptation k8s: service discovery and registration adaptation, configuration adaptation * Initial submission of the help charts script for openim API * change the help charts script * change the help charts script * change helm chart codes * change dockerfiles script * change chart script:add configmap mounts * change chart script:change repository * change chart script:msggateway add one service * change config.yaml * roll back some config values * change chart script:change Ingress rule with a rewrite annotation * add mysql charts scrible * change chart script:add mysql.config.yaml * add nfs provisioner charts * change chart script:add nfs.config.yaml * add ingress-nginx charts * change chart script:add ingress-nginx.config.yaml * add redis &mongodb charts * add kafka&minio charts * change chart script:change redis.values.yaml * change chart script:add redis.config.yaml * change chart script:change redis.config.yaml * change chart script:change mongodb.value.yaml * change chart script:change mongodb.value.yaml * change chart script:add mongodb.config.yaml * change chart script:change minio.values.yaml * change chart script:add minio.config.yaml * change chart script:change kafka.values.yaml * change chart script:add kafka.config.yaml * change chart script:change services.config.yaml * bug fix:Delete websocket's Port restrictions * bug fix:change port value * change chart script:Submit a stable version script * fix bug:Implement option interface * fix bug:change K8sDR.Register * change config.yaml * change chats script:minio service add ingress * change chats script:minio service add ingress * change chats script:kafka.replicaCount=3& change minio.api ingress * delete change chats script * change config.yaml * change openim.yaml * merge go.sum * Add monitoring function and struct for Prometheus on gin and GRPC * Add GRPC and gin server monitoring logic * Add GRPC and gin server monitoring logic2 * Add GRPC and gin server monitoring logic3 * Add GRPC and gin server monitoring logic4 * Add GRPC and gin server monitoring logic5 * Add GRPC and gin server monitoring logic6 * Add GRPC and gin server monitoring logic7 * delete:old monitoring code * add for test * fix bug:change packname * fix bug:delete getPromPort funciton * fix bug:delete getPromPort funciton * fix bug:change logs * fix bug:change registerName logic in GetGrpcCusMetrics function * add getPrometheus url api * fix:config path logic * fix:prometheus enable function * fix:prometheus enable function * fix:transfer Multi process monitoring logic * del:del not using manifest * fix:openim-msgtransfer.sh * fix:openim-msgtransfer.sh * cicd: robot automated Change * delete not using files * add prometheus docker-compose for monitor * fix prometheus.yaml * fix environment.sh * fix init-config.sh * fix init-config.sh * fix env_template.yaml * fix docker-compose.yml * fix docker-compose.yml * add openim_admin_front service * change openim-admin-front * del not using files * add node-exporter-dashaboard.yaml * cicd: robot automated Change * cicd: robot automated Change * feature: add alertmanager function * feature: add alertmanager function * feature: add alertmanager function * feature: add alertmanager function * feature: add alertmanager function * del:delete not using files * del:delete not using files * change:change to personal email info * fix:alertmanager.yml * fix:fix docker-compose.yml * del:not using files --------- Co-authored-by: lin.huang Co-authored-by: Xinwei Xiong <3293172751@qq.com> Co-authored-by: xuexihuang Co-authored-by: cubxxw --- deployments/templates/alertmanager.yml | 1 + docker-compose.yml | 1 - scripts/install/environment.sh | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deployments/templates/alertmanager.yml b/deployments/templates/alertmanager.yml index 95e96571d..47090f148 100644 --- a/deployments/templates/alertmanager.yml +++ b/deployments/templates/alertmanager.yml @@ -19,6 +19,7 @@ templates: - /etc/alertmanager/email.tmpl route: + group_by: ['alertname'] group_wait: 5s group_interval: 5s repeat_interval: 5m diff --git a/docker-compose.yml b/docker-compose.yml index 1b9b391b2..1a6626add 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,7 +100,6 @@ services: - KAFKA_CFG_NODE_ID=0 - KAFKA_CFG_PROCESS_ROLES=controller,broker - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@:9093 - - KAFKA_HEAP_OPTS:"-Xmx256m -Xms256m" - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://${DOCKER_BRIDGE_GATEWAY}:${KAFKA_PORT} - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index 777f88e18..6a87b44a6 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -282,7 +282,7 @@ readonly ALERTMANAGER_SMTP_REQUIRE_TLS=${ALERTMANAGER_SMTP_REQUIRE_TLS:-"false"} # SMTP HELO/EHLO标识符 readonly ALERTMANAGER_SMTP_HELLO=${ALERTMANAGER_SMTP_HELLO:-"xxx监控告警"} # 邮箱接收人 -readonly ALERTMANAGER_EMAIL_TO=${ALERTMANAGER_EMAIL_TO:-"{EMAIL_TO:-'alert@example.com'}"} +readonly ALERTMANAGER_EMAIL_TO=${ALERTMANAGER_EMAIL_TO:-"alert@example.com"} # 邮箱主题 readonly ALERTMANAGER_EMAIL_SUBJECT=${ALERTMANAGER_EMAIL_SUBJECT:-"{EMAIL_SUBJECT:-'[Alert] Notification'}"} # 是否发送已解决的告警 From a9153afc38f2b7e79c6959777e548deddc5deb4d Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Wed, 22 Nov 2023 17:31:37 +0800 Subject: [PATCH 02/18] perf: control ws write buffer (#1451) Signed-off-by: rfyiamcool --- internal/msggateway/init.go | 4 +++- internal/msggateway/long_conn.go | 9 +++++++-- internal/msggateway/n_ws_server.go | 5 ++++- internal/msggateway/options.go | 8 ++++++++ pkg/common/config/config.go | 1 + 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 12a6d3770..14c320c42 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -37,7 +37,9 @@ func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { WithPort(wsPort), WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)), WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second), - WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen)) + WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen), + WithWriteBufferSize(config.Config.LongConnSvr.WebsocketWriteBufferSize), + ) if err != nil { return err } diff --git a/internal/msggateway/long_conn.go b/internal/msggateway/long_conn.go index 604619eb5..93e5cc33f 100644 --- a/internal/msggateway/long_conn.go +++ b/internal/msggateway/long_conn.go @@ -50,10 +50,11 @@ type GWebSocket struct { protocolType int conn *websocket.Conn handshakeTimeout time.Duration + writeBufferSize int } -func newGWebSocket(protocolType int, handshakeTimeout time.Duration) *GWebSocket { - return &GWebSocket{protocolType: protocolType, handshakeTimeout: handshakeTimeout} +func newGWebSocket(protocolType int, handshakeTimeout time.Duration, wbs int) *GWebSocket { + return &GWebSocket{protocolType: protocolType, handshakeTimeout: handshakeTimeout, writeBufferSize: wbs} } func (d *GWebSocket) Close() error { @@ -65,6 +66,10 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er HandshakeTimeout: d.handshakeTimeout, CheckOrigin: func(r *http.Request) bool { return true }, } + if d.writeBufferSize > 0 { // default is 4kb. + upgrader.WriteBufferSize = d.writeBufferSize + } + conn, err := upgrader.Upgrade(w, r, nil) if err != nil { return err diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index 10dd988d1..a249ff70f 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -68,6 +68,7 @@ type WsServer struct { onlineUserNum atomic.Int64 onlineUserConnNum atomic.Int64 handshakeTimeout time.Duration + writeBufferSize int validate *validator.Validate cache cache.MsgModel userClient *rpcclient.UserRpcClient @@ -137,6 +138,7 @@ func NewWsServer(opts ...Option) (*WsServer, error) { return &WsServer{ port: config.port, wsMaxConnNum: config.maxConnNum, + writeBufferSize: config.writeBufferSize, handshakeTimeout: config.handshakeTimeout, clientPool: sync.Pool{ New: func() interface{} { @@ -430,7 +432,8 @@ func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) { httpError(connContext, errs.ErrTokenNotExist.Wrap()) return } - wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout) + + wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize) err = wsLongConn.GenerateLongConn(w, r) if err != nil { httpError(connContext, err) diff --git a/internal/msggateway/options.go b/internal/msggateway/options.go index 24cbbe43f..6513ac5dc 100644 --- a/internal/msggateway/options.go +++ b/internal/msggateway/options.go @@ -27,6 +27,8 @@ type ( handshakeTimeout time.Duration // 允许消息最大长度 messageMaxMsgLength int + // websocket write buffer, default: 4096, 4kb. + writeBufferSize int } ) @@ -53,3 +55,9 @@ func WithMessageMaxMsgLength(length int) Option { opt.messageMaxMsgLength = length } } + +func WithWriteBufferSize(size int) Option { + return func(opt *configs) { + opt.writeBufferSize = size + } +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index fdb1cee00..1e9df7813 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -196,6 +196,7 @@ type configStruct struct { WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"` WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"` WebsocketTimeout int `yaml:"websocketTimeout"` + WebsocketWriteBufferSize int `yaml:"websocketWriteBufferSize"` } `yaml:"longConnSvr"` Push struct { From 1f7dfa33d7c30f0a8ffd9a5d787aef0d4fcec267 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Sun, 26 Nov 2023 11:19:12 +0800 Subject: [PATCH 03/18] Update README.md (#1477) --- deployments/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployments/README.md b/deployments/README.md index 0f73a553e..b24babb31 100644 --- a/deployments/README.md +++ b/deployments/README.md @@ -84,8 +84,8 @@ $ sudo sealos run labring/kubernetes:v1.25.0 labring/helm:v3.8.2 labring/calico: If you are local, you can also use Kind and Minikube to test, for example, using Kind: ```bash -$ sGO111MODULE="on" go get sigs.k8s.io/kind@v0.11.1 -$ skind create cluster +$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.11.1 +$ kind create cluster ``` ### Installing helm @@ -174,4 +174,4 @@ cp ../config/notification.yaml ./charts/generated-configs/notification.yaml ```bash helmfile apply -``` \ No newline at end of file +``` From 403cfb60559a5332b0c5aa2e5b65fa8d9a542019 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Sun, 26 Nov 2023 20:16:02 +0800 Subject: [PATCH 04/18] perf: redis block with keys command (#1423) Signed-off-by: rfyiamcool --- pkg/common/db/cache/msg.go | 36 ++++++++++++++++++------- pkg/common/db/cache/msg_test.go | 47 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 6d0ee8c67..282d1d1c1 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -645,19 +645,35 @@ func (c *msgCache) PipeDeleteMessages(ctx context.Context, conversationID string } func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error { - vals, err := c.rdb.Keys(ctx, c.allMessageCacheKey(conversationID)).Result() - if errors.Is(err, redis.Nil) { - return nil - } - if err != nil { - return errs.Wrap(err) - } - for _, v := range vals { - if err := c.rdb.Del(ctx, v).Err(); err != nil { + var ( + cursor uint64 + keys []string + err error + + key = c.allMessageCacheKey(conversationID) + ) + + for { + // 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) } + + 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 { diff --git a/pkg/common/db/cache/msg_test.go b/pkg/common/db/cache/msg_test.go index 3fddf5965..a5be018ed 100644 --- a/pkg/common/db/cache/msg_test.go +++ b/pkg/common/db/cache/msg_test.go @@ -385,3 +385,50 @@ func testParallelDeleteMessagesMix(t *testing.T, cid string, seqs []int64, input 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)) +} From e4046994cf07c27cf35581a624b360d53450a7a0 Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:22:41 +0800 Subject: [PATCH 05/18] fix: update user's info will modify user create time when modify user's nickname or avatar. (#1446) --- pkg/common/convert/user.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index abb3a2144..4ca1899be 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -15,8 +15,6 @@ package convert import ( - "time" - "github.com/OpenIMSDK/protocol/sdkws" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" @@ -43,7 +41,6 @@ func UserPb2DB(user *sdkws.UserInfo) *relationtb.UserModel { userDB.Nickname = user.Nickname userDB.FaceURL = user.FaceURL userDB.Ex = user.Ex - userDB.CreateTime = time.UnixMilli(user.CreateTime) userDB.AppMangerLevel = user.AppMangerLevel userDB.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt return &userDB From 3cecbbc69ac97f3ddea92bc9090b7af4ecb1d511 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Sun, 26 Nov 2023 20:25:37 +0800 Subject: [PATCH 06/18] fix: grace shutdown for api server (#1439) * fix: add grace shutdown for api server Signed-off-by: rfyiamcool * fix: add grace shutdown for api server Signed-off-by: rfyiamcool --------- Signed-off-by: rfyiamcool --- cmd/openim-api/main.go | 45 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/cmd/openim-api/main.go b/cmd/openim-api/main.go index 1375655ba..cb9b09802 100644 --- a/cmd/openim-api/main.go +++ b/cmd/openim-api/main.go @@ -18,11 +18,13 @@ import ( "context" "fmt" "net" + "net/http" _ "net/http/pprof" + "os" + "os/signal" "strconv" - - ginProm "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" - "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" + "syscall" + "time" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/discoveryregistry" @@ -33,6 +35,8 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" + ginProm "github.com/openimsdk/open-im-server/v3/pkg/common/ginprometheus" + "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" ) func main() { @@ -51,13 +55,12 @@ func run(port int, proPort int) error { if port == 0 || proPort == 0 { err := "port or proPort is empty:" + strconv.Itoa(port) + "," + strconv.Itoa(proPort) log.ZError(context.Background(), err, nil) - return fmt.Errorf(err) } + rdb, err := cache.NewRedis() if err != nil { log.ZError(context.Background(), "Failed to initialize Redis", err) - return err } log.ZInfo(context.Background(), "api start init discov client") @@ -68,30 +71,29 @@ func run(port int, proPort int) error { client, err = kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { log.ZError(context.Background(), "Failed to initialize discovery register", err) - return err } + if err = client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { log.ZError(context.Background(), "Failed to create RPC root nodes", err) - return err } + log.ZInfo(context.Background(), "api register public config to discov") if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.Config.EncodeConfig()); err != nil { log.ZError(context.Background(), "Failed to register public config to discov", err) - return err } + log.ZInfo(context.Background(), "api register public config to discov success") router := api.NewGinRouter(client, rdb) - ////////////////////////////// if config.Config.Prometheus.Enable { p := ginProm.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p.SetListenAddress(fmt.Sprintf(":%d", proPort)) p.Use(router) } - ///////////////////////////////// log.ZInfo(context.Background(), "api init router success") + var address string if config.Config.Api.ListenIP != "" { address = net.JoinHostPort(config.Config.Api.ListenIP, strconv.Itoa(port)) @@ -100,10 +102,25 @@ func run(port int, proPort int) error { } log.ZInfo(context.Background(), "start api server", "address", address, "OpenIM version", config.Version) - err = router.Run(address) - if err != nil { - log.ZError(context.Background(), "api run failed", err, "address", address) - + server := http.Server{Addr: address, Handler: router} + go func() { + err = server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + log.ZError(context.Background(), "api run failed", err, "address", address) + os.Exit(1) + } + }() + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + <-sigs + + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + // graceful shutdown operation. + if err := server.Shutdown(ctx); err != nil { + log.ZError(context.Background(), "failed to api-server shutdown", err) return err } From f935d36715ce90ffe1d8373384f2472cab360881 Mon Sep 17 00:00:00 2001 From: Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:49:31 +0800 Subject: [PATCH 07/18] fix: wrong single message read state. (#1443) * fix: wrong single message read state. * Update as_read.go * Update as_read.go * Update as_read.go --------- Co-authored-by: Xinwei Xiong <3293172751@qq.com> --- internal/rpc/msg/as_read.go | 79 +++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index 6e3bbe987..3311fa5b7 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -17,9 +17,12 @@ package msg import ( "context" + utils2 "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/errs" @@ -88,10 +91,7 @@ func (m *msgServer) SetConversationHasReadSeq( return &msg.SetConversationHasReadSeqResp{}, nil } -func (m *msgServer) MarkMsgsAsRead( - ctx context.Context, - req *msg.MarkMsgsAsReadReq, -) (resp *msg.MarkMsgsAsReadResp, err error) { +func (m *msgServer) MarkMsgsAsRead(ctx context.Context, req *msg.MarkMsgsAsReadReq) (resp *msg.MarkMsgsAsReadResp, err error) { if len(req.Seqs) < 1 { return nil, errs.ErrArgs.Wrap("seqs must not be empty") } @@ -127,10 +127,7 @@ func (m *msgServer) MarkMsgsAsRead( return &msg.MarkMsgsAsReadResp{}, nil } -func (m *msgServer) MarkConversationAsRead( - ctx context.Context, - req *msg.MarkConversationAsReadReq, -) (resp *msg.MarkConversationAsReadResp, err error) { +func (m *msgServer) MarkConversationAsRead(ctx context.Context, req *msg.MarkConversationAsReadReq) (resp *msg.MarkConversationAsReadResp, err error) { conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID) if err != nil { return nil, err @@ -139,49 +136,47 @@ func (m *msgServer) MarkConversationAsRead( if err != nil && errs.Unwrap(err) != redis.Nil { return nil, err } - var seqs []int64 + seqs := generateSeqs(hasReadSeq, req) - log.ZDebug(ctx, "MarkConversationAsRead", "hasReadSeq", hasReadSeq, - "req.HasReadSeq", req.HasReadSeq) - if conversation.ConversationType == constant.SingleChatType { - for i := hasReadSeq + 1; i <= req.HasReadSeq; i++ { - seqs = append(seqs, i) + if len(seqs) > 0 || req.HasReadSeq > hasReadSeq { + err = m.updateReadStatus(ctx, req, conversation, seqs, hasReadSeq) + if err != nil { + return nil, err } + } + return &msg.MarkConversationAsReadResp{}, nil +} - if len(seqs) > 0 { - log.ZDebug(ctx, "MarkConversationAsRead", "seqs", seqs, "conversationID", req.ConversationID) - if err = m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, seqs); err != nil { - return nil, err - } - } - if req.HasReadSeq > hasReadSeq { - err = m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq) - if err != nil { - return nil, err - } - hasReadSeq = req.HasReadSeq - } - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, - m.conversationAndGetRecvID(conversation, req.UserID), seqs, hasReadSeq); err != nil { - return nil, err +func generateSeqs(hasReadSeq int64, req *msg.MarkConversationAsReadReq) []int64 { + var seqs []int64 + for _, val := range req.Seqs { + if val > hasReadSeq && !utils2.Contain(val, seqs...) { + seqs = append(seqs, val) } - } else if conversation.ConversationType == constant.SuperGroupChatType || - conversation.ConversationType == constant.NotificationChatType { - if req.HasReadSeq > hasReadSeq { - err = m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq) - if err != nil { - return nil, err - } - hasReadSeq = req.HasReadSeq + } + return seqs +} + +func (m *msgServer) updateReadStatus(ctx context.Context, req *msg.MarkConversationAsReadReq, conversation *conversation.Conversation, seqs []int64, hasReadSeq int64) error { + if conversation.ConversationType == constant.SingleChatType && len(seqs) > 0 { + log.ZDebug(ctx, "MarkConversationAsRead", "seqs", seqs, "conversationID", req.ConversationID) + if err := m.MsgDatabase.MarkSingleChatMsgsAsRead(ctx, req.UserID, req.ConversationID, seqs); err != nil { + return err } - if err = m.sendMarkAsReadNotification(ctx, req.ConversationID, constant.SingleChatType, req.UserID, - req.UserID, seqs, hasReadSeq); err != nil { - return nil, err + } + + if req.HasReadSeq > hasReadSeq { + if err := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); err != nil { + return err } + } + recvID := m.conversationAndGetRecvID(conversation, req.UserID) + if conversation.ConversationType == constant.SuperGroupChatType || conversation.ConversationType == constant.NotificationChatType { + recvID = req.UserID } - return &msg.MarkConversationAsReadResp{}, nil + return m.sendMarkAsReadNotification(ctx, req.ConversationID, conversation.ConversationType, req.UserID, recvID, seqs, req.HasReadSeq) } func (m *msgServer) sendMarkAsReadNotification( From 100926da0ee4109f60b6700c28b015000f7e5f2e Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Tue, 28 Nov 2023 14:44:02 +0800 Subject: [PATCH 08/18] docs: add openim search test (#1485) --- scripts/install/test.sh | 54 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/scripts/install/test.sh b/scripts/install/test.sh index 7bcea3b82..eb3f6a200 100755 --- a/scripts/install/test.sh +++ b/scripts/install/test.sh @@ -1168,6 +1168,40 @@ EOF openim::test::check_error "$response" } +# Searches for messages. +openim::test::search_msg() { + local sendID="${1}" + local recvID="${2}" + local msgType="${3}" + local sendTime="${4}" + local sessionType="${5}" + local pageNumber="${6}" + local showNumber="${7}" + + # Construct the request body + local request_body=$(cat < Date: Tue, 28 Nov 2023 15:26:46 +0800 Subject: [PATCH 09/18] feat: add callback func (#1480) * feat:add callback func * fix: fix the error * fix: fix the error of repalce * fix: fix the error of repalce --- deployments/templates/openim.yaml | 153 +++++++++++++++++-------- docs/contrib/environment.md | 8 +- internal/msggateway/callback.go | 21 +++- internal/push/callback.go | 19 ++- internal/rpc/friend/callback.go | 46 ++++++-- internal/rpc/friend/friend.go | 7 ++ internal/rpc/group/callback.go | 184 +++++++++++++++++++++++------- internal/rpc/group/group.go | 57 +++++++++ internal/rpc/msg/as_read.go | 10 ++ internal/rpc/msg/callback.go | 54 +++++---- internal/rpc/user/callback.go | 64 +++++++++-- internal/rpc/user/user.go | 10 ++ pkg/callbackstruct/common.go | 11 +- pkg/callbackstruct/constant.go | 33 ++++++ pkg/callbackstruct/friend.go | 45 +++++++- pkg/callbackstruct/group.go | 132 ++++++++++++++++++++- pkg/callbackstruct/message.go | 43 +++++++ pkg/callbackstruct/user.go | 35 +++++- pkg/common/config/config.go | 13 +++ pkg/common/http/http_client.go | 16 +-- scripts/install/environment.sh | 4 + 21 files changed, 801 insertions(+), 164 deletions(-) create mode 100644 pkg/callbackstruct/constant.go diff --git a/deployments/templates/openim.yaml b/deployments/templates/openim.yaml index 44a28adff..c0e552c24 100644 --- a/deployments/templates/openim.yaml +++ b/deployments/templates/openim.yaml @@ -164,7 +164,7 @@ object: # These ports are passed into the program by the script and are not recommended to modify # For launching multiple programs, just fill in multiple ports separated by commas # For example, [10110, 10111] -rpcPort: +rpcPort: openImUserPort: [ ${OPENIM_USER_PORT} ] openImFriendPort: [ ${OPENIM_FRIEND_PORT} ] openImMessagePort: [ ${OPENIM_MESSAGE_PORT} ] @@ -314,68 +314,125 @@ iosPush: callback: url: beforeSendSingleMsg: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} afterSendSingleMsg: - enable: false - timeout: 5 + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeSendGroupMsg: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} afterSendGroupMsg: - enable: false - timeout: 5 + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} msgModify: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} userOnline: - enable: false - timeout: 5 + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} userOffline: - enable: false - timeout: 5 + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} userKickOff: - enable: false - timeout: 5 + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} offlinePush: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} onlinePush: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} superGroupOnlinePush: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeAddFriend: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeUpdateUserInfo: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeCreateGroup: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterCreateGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeMemberJoinGroup: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} beforeSetGroupMemberInfo: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} setMessageReactionExtensions: - enable: false - timeout: 5 - failedContinue: true + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + quitGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + killGroupMember: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + dismissGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + joinGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + groupMsgRead: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + singleMsgRead: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + updateUserInfo: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + beforeUserRegister: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterUserRegister: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + transferGroupOwner: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + beforeSetFriendRemark: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterSetFriendRemark: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} ###################### Prometheus ###################### # Prometheus configuration for various services @@ -395,4 +452,4 @@ prometheus: conversationPrometheusPort: [ ${CONVERSATION_PROM_PORT} ] rtcPrometheusPort: [ ${RTC_PROM_PORT} ] thirdPrometheusPort: [ ${THIRD_PROM_PORT} ] - messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports \ No newline at end of file + messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index 221efdf03..8e0cf2572 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -466,7 +466,7 @@ This section involves configuring the log settings, including storage location, This section involves setting up additional configuration variables for Websocket, Push Notifications, and Chat. | Parameter | Example Value | Description | -| ----------------------- | ----------------- | ---------------------------------- | +|-------------------------|-------------------|------------------------------------| | WEBSOCKET_MAX_CONN_NUM | "100000" | Maximum Websocket connections | | WEBSOCKET_MAX_MSG_LEN | "4096" | Maximum Websocket message length | | WEBSOCKET_TIMEOUT | "10" | Websocket timeout | @@ -500,9 +500,9 @@ This section involves setting up additional configuration variables for Websocke | TOKEN_EXPIRE | "90" | Token Expiry Time | | FRIEND_VERIFY | "false" | Friend Verification Enable | | IOS_PUSH_SOUND | "xxx" | iOS | - - - +| CALLBACK_ENABLE | "true" | Enable callback | | | | +| CALLBACK_TIMEOUT | "5" | Maximum timeout for callback call | +| CALLBACK_FAILED_CONTINUE| "true" | fails to continue to the next step | ### 2.20. Prometheus Configuration This section involves configuring Prometheus, including enabling/disabling it and setting up ports for various services. diff --git a/internal/msggateway/callback.go b/internal/msggateway/callback.go index d7320a304..7d5381754 100644 --- a/internal/msggateway/callback.go +++ b/internal/msggateway/callback.go @@ -37,7 +37,7 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp req := cbapi.CallbackUserOnlineReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackUserOnlineCommand, + CallbackCommand: cbapi.CallbackUserOnlineCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -49,7 +49,10 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp ConnID: connID, } resp := cbapi.CommonCallbackResp{} - return http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline) + if err := http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline); err != nil { + return err + } + return nil } func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error { @@ -59,7 +62,7 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con req := &cbapi.CallbackUserOfflineReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackUserOfflineCommand, + CallbackCommand: cbapi.CallbackUserOfflineCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -70,7 +73,10 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con ConnID: connID, } resp := &cbapi.CallbackUserOfflineResp{} - return http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline) + if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { + return err + } + return nil } func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error { @@ -80,7 +86,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err req := &cbapi.CallbackUserKickOffReq{ UserStatusCallbackReq: cbapi.UserStatusCallbackReq{ UserStatusBaseCallback: cbapi.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackUserKickOffCommand, + CallbackCommand: cbapi.CallbackUserKickOffCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: platformID, Platform: constant.PlatformIDToName(platformID), @@ -90,7 +96,10 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err Seq: time.Now().UnixMilli(), } resp := &cbapi.CommonCallbackResp{} - return http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline) + if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { + return err + } + return nil } // func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID diff --git a/internal/push/callback.go b/internal/push/callback.go index c646df3e2..2085493c5 100644 --- a/internal/push/callback.go +++ b/internal/push/callback.go @@ -19,7 +19,6 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" @@ -44,7 +43,7 @@ func callbackOfflinePush( req := &callbackstruct.CallbackBeforePushReq{ UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackOfflinePushCommand, + CallbackCommand: callbackstruct.CallbackOfflinePushCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: int(msg.SenderPlatformID), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), @@ -62,9 +61,6 @@ func callbackOfflinePush( } resp := &callbackstruct.CallbackBeforePushResp{} if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } if len(resp.UserIDs) != 0 { @@ -83,7 +79,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat req := callbackstruct.CallbackBeforePushReq{ UserStatusBatchCallbackReq: callbackstruct.UserStatusBatchCallbackReq{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackOnlinePushCommand, + CallbackCommand: callbackstruct.CallbackOnlinePushCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: int(msg.SenderPlatformID), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), @@ -99,7 +95,10 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat Content: GetContent(msg), } resp := &callbackstruct.CallbackBeforePushResp{} - return http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush) + if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush); err != nil { + return err + } + return nil } func callbackBeforeSuperGroupOnlinePush( @@ -113,7 +112,7 @@ func callbackBeforeSuperGroupOnlinePush( } req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ UserStatusBaseCallback: callbackstruct.UserStatusBaseCallback{ - CallbackCommand: constant.CallbackSuperGroupOnlinePushCommand, + CallbackCommand: callbackstruct.CallbackSuperGroupOnlinePushCommand, OperationID: mcontext.GetOperationID(ctx), PlatformID: int(msg.SenderPlatformID), Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)), @@ -129,11 +128,9 @@ func callbackBeforeSuperGroupOnlinePush( } resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } + return nil if len(resp.UserIDs) != 0 { *pushToUserIDs = resp.UserIDs } diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index bb687773e..d3b853ef9 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -16,12 +16,9 @@ package friend import ( "context" + "github.com/OpenIMSDK/tools/utils" - "github.com/OpenIMSDK/protocol/constant" pbfriend "github.com/OpenIMSDK/protocol/friend" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mcontext" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" @@ -32,17 +29,48 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend return nil } cbReq := &cbapi.CallbackBeforeAddFriendReq{ - CallbackCommand: constant.CallbackBeforeAddFriendCommand, + CallbackCommand: cbapi.CallbackBeforeAddFriendCommand, FromUserID: req.FromUserID, ToUserID: req.ToUserID, ReqMsg: req.ReqMsg, - OperationID: mcontext.GetOperationID(ctx), } resp := &cbapi.CallbackBeforeAddFriendResp{} if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } + return err + } + return nil +} + +func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { + if !config.Config.Callback.CallbackBeforeSetFriendRemark.Enable { + return nil + } + cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ + CallbackCommand: cbapi.CallbackBeforeSetFriendRemark, + OwnerUserID: req.OwnerUserID, + FriendUserID: req.FriendUserID, + Remark: req.Remark, + } + resp := &cbapi.CallbackBeforeSetFriendRemarkResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { + return err + } + utils.NotNilReplace(&req.Remark, &resp.Remark) + return nil +} + +func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { + if !config.Config.Callback.CallbackAfterSetFriendRemark.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ + CallbackCommand: cbapi.CallbackAfterSetFriendRemark, + OwnerUserID: req.OwnerUserID, + FriendUserID: req.FriendUserID, + Remark: req.Remark, + } + resp := &cbapi.CallbackAfterSetFriendRemarkResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { return err } return nil diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index c563f77fe..24014ace1 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -217,6 +217,10 @@ func (s *friendServer) SetFriendRemark( req *pbfriend.SetFriendRemarkReq, ) (resp *pbfriend.SetFriendRemarkResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") + + if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { + return nil, err + } resp = &pbfriend.SetFriendRemarkResp{} if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err @@ -228,6 +232,9 @@ func (s *friendServer) SetFriendRemark( if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil { return nil, err } + if err := CallbackAfterSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { + return nil, err + } s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID) return resp, nil } diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index 38174738b..13f9737b5 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -21,10 +21,11 @@ import ( "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + pbgroup "github.com/OpenIMSDK/protocol/group" + "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -37,7 +38,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) ( return nil } cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ - CallbackCommand: constant.CallbackBeforeCreateGroupCommand, + CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand, OperationID: mcontext.GetOperationID(ctx), GroupInfo: req.GroupInfo, } @@ -58,17 +59,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) ( }) } resp := &callbackstruct.CallbackBeforeCreateGroupResp{} - err = http.CallBackPostReturn( - ctx, - config.Config.Callback.CallbackUrl, - cbReq, - resp, - config.Config.Callback.CallbackBeforeCreateGroup, - ) - if err != nil { - if err == errs.ErrCallbackContinue { - return nil - } + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeCreateGroup); err != nil { return err } utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) @@ -86,6 +77,37 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) ( return nil } +func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) { + if !config.Config.Callback.CallbackAfterCreateGroup.Enable { + return nil + } + cbReq := &callbackstruct.CallbackAfterCreateGroupReq{ + CallbackCommand: callbackstruct.CallbackAfterCreateGroupCommand, + GroupInfo: req.GroupInfo, + } + cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ + UserID: req.OwnerUserID, + RoleLevel: constant.GroupOwner, + }) + for _, userID := range req.AdminUserIDs { + cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ + UserID: userID, + RoleLevel: constant.GroupAdmin, + }) + } + for _, userID := range req.MemberUserIDs { + cbReq.InitMemberList = append(cbReq.InitMemberList, &apistruct.GroupAddMemberInfo{ + UserID: userID, + RoleLevel: constant.GroupOrdinaryUsers, + }) + } + resp := &callbackstruct.CallbackAfterCreateGroupResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterCreateGroup); err != nil { + return err + } + return nil +} + func CallbackBeforeMemberJoinGroup( ctx context.Context, groupMember *relation.GroupMemberModel, @@ -95,25 +117,14 @@ func CallbackBeforeMemberJoinGroup( return nil } callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ - CallbackCommand: constant.CallbackBeforeMemberJoinGroupCommand, - OperationID: mcontext.GetOperationID(ctx), + CallbackCommand: callbackstruct.CallbackBeforeMemberJoinGroupCommand, GroupID: groupMember.GroupID, UserID: groupMember.UserID, Ex: groupMember.Ex, GroupEx: groupEx, } resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} - err = http.CallBackPostReturn( - ctx, - config.Config.Callback.CallbackUrl, - callbackReq, - resp, - config.Config.Callback.CallbackBeforeMemberJoinGroup, - ) - if err != nil { - if err == errs.ErrCallbackContinue { - return nil - } + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeMemberJoinGroup); err != nil { return err } if resp.MuteEndTime != nil { @@ -131,8 +142,7 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe return nil } callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ - CallbackCommand: constant.CallbackBeforeSetGroupMemberInfoCommand, - OperationID: mcontext.GetOperationID(ctx), + CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, GroupID: req.GroupID, UserID: req.UserID, } @@ -149,17 +159,7 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe callbackReq.Ex = &req.Ex.Value } resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} - err = http.CallBackPostReturn( - ctx, - config.Config.Callback.CallbackUrl, - callbackReq, - resp, - config.Config.Callback.CallbackBeforeSetGroupMemberInfo, - ) - if err != nil { - if err == errs.ErrCallbackContinue { - return nil - } + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupMemberInfo); err != nil { return err } if resp.FaceURL != nil { @@ -176,3 +176,109 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe } return nil } + +func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { + if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { + return nil + } + callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ + CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, + GroupID: req.GroupID, + UserID: req.UserID, + } + if req.Nickname != nil { + callbackReq.Nickname = &req.Nickname.Value + } + if req.FaceURL != nil { + callbackReq.FaceURL = &req.FaceURL.Value + } + if req.RoleLevel != nil { + callbackReq.RoleLevel = &req.RoleLevel.Value + } + if req.Ex != nil { + callbackReq.Ex = &req.Ex.Value + } + resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupMemberInfo); err != nil { + return err + } + return nil +} + +func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) { + if !config.Config.Callback.CallbackQuitGroup.Enable { + return nil + } + cbReq := &callbackstruct.CallbackQuitGroupReq{ + CallbackCommand: callbackstruct.CallbackQuitGroupCommand, + GroupID: req.GroupID, + UserID: req.UserID, + } + resp := &callbackstruct.CallbackQuitGroupResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + return err + } + return nil +} + +func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (err error) { + if !config.Config.Callback.CallbackKillGroupMember.Enable { + return nil + } + cbReq := &callbackstruct.CallbackKillGroupMemberReq{ + CallbackCommand: callbackstruct.CallbackKillGroupCommand, + GroupID: req.GroupID, + KickedUserIDs: req.KickedUserIDs, + } + resp := &callbackstruct.CallbackKillGroupMemberResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + return err + } + return nil +} + +func CallbackDismissGroup(ctx context.Context, req *callbackstruct.CallbackDisMissGroupReq) (err error) { + if !config.Config.Callback.CallbackDismissGroup.Enable { + return nil + } + req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand + resp := &callbackstruct.CallbackDisMissGroupResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackQuitGroup); err != nil { + return err + } + return nil +} + +func CallbackApplyJoinGroupBefore(ctx context.Context, req *callbackstruct.CallbackJoinGroupReq) (err error) { + if !config.Config.Callback.CallbackBeforeJoinGroup.Enable { + return nil + } + + req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand + + resp := &callbackstruct.CallbackJoinGroupResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil { + return err + } + + return nil +} + +func CallbackTransferGroupOwnerAfter(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) { + if !config.Config.Callback.CallbackTransferGroupOwnerAfter.Enable { + return nil + } + + cbReq := &callbackstruct.CallbackTransferGroupOwnerReq{ + CallbackCommand: callbackstruct.CallbackTransferGroupOwnerAfter, + GroupID: req.GroupID, + OldOwnerUserID: req.OldOwnerUserID, + NewOwnerUserID: req.NewOwnerUserID, + } + + resp := &callbackstruct.CallbackTransferGroupOwnerResp{} + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeJoinGroup); err != nil { + return err + } + return nil +} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 85b78cfb2..227b7959d 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -26,6 +26,8 @@ import ( "strings" "time" + "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" @@ -225,6 +227,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR if len(userMap) != len(userIDs) { return nil, errs.ErrUserIDNotFound.Wrap("user not found") } + // Callback Before create Group if err := CallbackBeforeCreateGroup(ctx, req); err != nil { return nil, err } @@ -298,6 +301,17 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR } s.Notification.GroupCreatedNotification(ctx, tips) } + reqCallBackAfter := &pbgroup.CreateGroupReq{ + MemberUserIDs: userIDs, + GroupInfo: resp.GroupInfo, + OwnerUserID: req.OwnerUserID, + AdminUserIDs: req.AdminUserIDs, + } + + if err := CallbackAfterCreateGroup(ctx, reqCallBackAfter); err != nil { + return nil, err + } + return resp, nil } @@ -606,6 +620,10 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if err := s.deleteMemberAndSetConversationSeq(ctx, req.GroupID, req.KickedUserIDs); err != nil { return nil, err } + + if err := CallbackKillGroupMember(ctx, req); err != nil { + return nil, err + } return resp, nil } @@ -816,6 +834,17 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if group.Status == constant.GroupStatusDismissed { return nil, errs.ErrDismissedAlready.Wrap() } + + reqCall := &callbackstruct.CallbackJoinGroupReq{ + GroupID: req.GroupID, + GroupType: string(group.GroupType), + ApplyID: req.InviterUserID, + ReqMessage: req.ReqMessage, + } + + if err = CallbackApplyJoinGroupBefore(ctx, reqCall); err != nil { + return nil, err + } _, err = s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) if err == nil { return nil, errs.ErrArgs.Wrap("already in group") @@ -900,6 +929,10 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) return nil, err } + // callback + if err := CallbackQuitGroup(ctx, req); err != nil { + return nil, err + } return resp, nil } @@ -1031,6 +1064,10 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans if err := s.GroupDatabase.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil { return nil, err } + + if err := CallbackTransferGroupOwnerAfter(ctx, req); err != nil { + return nil, err + } s.Notification.GroupOwnerTransferredNotification(ctx, req) return resp, nil } @@ -1201,6 +1238,20 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou s.Notification.GroupDismissedNotification(ctx, tips) } } + membersID, err := s.GroupDatabase.FindGroupMemberUserID(ctx, group.GroupID) + if err != nil { + return nil, err + } + reqCall := &callbackstruct.CallbackDisMissGroupReq{ + GroupID: req.GroupID, + OwnerID: owner.UserID, + MembersID: membersID, + GroupType: string(group.GroupType), + } + if err := CallbackDismissGroup(ctx, reqCall); err != nil { + return nil, err + } + return resp, nil } @@ -1439,6 +1490,12 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } } } + for i := 0; i < len(req.Members); i++ { + if err := CallbackAfterSetGroupMemberInfo(ctx, req.Members[i]); err != nil { + return nil, err + } + } + return resp, nil } diff --git a/internal/rpc/msg/as_read.go b/internal/rpc/msg/as_read.go index 3311fa5b7..49113aa0b 100644 --- a/internal/rpc/msg/as_read.go +++ b/internal/rpc/msg/as_read.go @@ -16,6 +16,7 @@ package msg import ( "context" + cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" utils2 "github.com/OpenIMSDK/tools/utils" @@ -164,6 +165,15 @@ func (m *msgServer) updateReadStatus(ctx context.Context, req *msg.MarkConversat return err } } + reqCall := &cbapi.CallbackGroupMsgReadReq{ + SendID: conversation.OwnerUserID, + ReceiveID: req.UserID, + UnreadMsgNum: req.HasReadSeq, + ContentType: int64(conversation.ConversationType), + } + if err := CallbackGroupMsgRead(ctx, reqCall); err != nil { + return err + } if req.HasReadSeq > hasReadSeq { if err := m.MsgDatabase.SetHasReadSeq(ctx, req.UserID, req.ConversationID, req.HasReadSeq); err != nil { diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 68586ba85..85c002bf3 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -16,13 +16,11 @@ package msg import ( "context" - "github.com/OpenIMSDK/protocol/sdkws" "google.golang.org/protobuf/proto" "github.com/OpenIMSDK/protocol/constant" pbchat "github.com/OpenIMSDK/protocol/msg" - "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" @@ -74,14 +72,11 @@ func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) er return nil } req := &cbapi.CallbackBeforeSendSingleMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendSingleMsgCommand), + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendSingleMsgCommand), RecvID: msg.MsgData.RecvID, } resp := &cbapi.CallbackBeforeSendSingleMsgResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } return nil @@ -92,14 +87,11 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err return nil } req := &cbapi.CallbackAfterSendSingleMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackAfterSendSingleMsgCommand), + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendSingleMsgCommand), RecvID: msg.MsgData.RecvID, } resp := &cbapi.CallbackAfterSendSingleMsgResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } return nil @@ -110,14 +102,11 @@ func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) err return nil } req := &cbapi.CallbackAfterSendGroupMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackBeforeSendGroupMsgCommand), + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendGroupMsgCommand), GroupID: msg.MsgData.GroupID, } resp := &cbapi.CallbackBeforeSendGroupMsgResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } return nil @@ -128,14 +117,11 @@ func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) erro return nil } req := &cbapi.CallbackAfterSendGroupMsgReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackAfterSendGroupMsgCommand), + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackAfterSendGroupMsgCommand), GroupID: msg.MsgData.GroupID, } resp := &cbapi.CallbackAfterSendGroupMsgResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } return nil @@ -146,13 +132,10 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { return nil } req := &cbapi.CallbackMsgModifyCommandReq{ - CommonCallbackReq: toCommonCallback(ctx, msg, constant.CallbackMsgModifyCommand), + CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand), } resp := &cbapi.CallbackMsgModifyCommandResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } if resp.Content != nil { @@ -177,3 +160,30 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) return nil } + +func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error { + if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { + return nil + } + req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand + + resp := &cbapi.CallbackGroupMsgReadResp{} + if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { + return err + } + return nil +} + +func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgReadReq) error { + if !config.Config.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text { + return nil + } + req.CallbackCommand = cbapi.CallbackSingleMsgRead + + resp := &cbapi.CallbackGroupMsgReadResp{} + + if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { + return err + } + return nil +} diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go index 8f6ceef23..01de2734d 100644 --- a/internal/rpc/user/callback.go +++ b/internal/rpc/user/callback.go @@ -16,11 +16,7 @@ package user import ( "context" - - "github.com/OpenIMSDK/protocol/constant" pbuser "github.com/OpenIMSDK/protocol/user" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" @@ -33,17 +29,13 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf return nil } cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ - CallbackCommand: constant.CallbackBeforeUpdateUserInfoCommand, - OperationID: mcontext.GetOperationID(ctx), + CallbackCommand: cbapi.CallbackBeforeUpdateUserInfoCommand, UserID: req.UserInfo.UserID, FaceURL: &req.UserInfo.FaceURL, Nickname: &req.UserInfo.Nickname, } resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { - if err == errs.ErrCallbackContinue { - return nil - } return err } utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) @@ -51,3 +43,57 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname) return nil } + +func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error { + if !config.Config.Callback.CallbackAfterUpdateUserInfo.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{ + CallbackCommand: cbapi.CallbackAfterUpdateUserInfoCommand, + UserID: req.UserInfo.UserID, + FaceURL: req.UserInfo.FaceURL, + Nickname: req.UserInfo.Nickname, + } + resp := &cbapi.CallbackAfterUpdateUserInfoResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + return err + } + return nil +} + +func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { + if !config.Config.Callback.CallbackBeforeUserRegister.Enable { + return nil + } + cbReq := &cbapi.CallbackBeforeUserRegisterReq{ + CallbackCommand: cbapi.CallbackBeforeUserRegisterCommand, + Secret: req.Secret, + Users: req.Users, + } + + resp := &cbapi.CallbackBeforeUserRegisterResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + return err + } + if len(resp.Users) != 0 { + req.Users = resp.Users + } + return nil +} + +func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { + if !config.Config.Callback.CallbackAfterUserRegister.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterUserRegisterReq{ + CallbackCommand: cbapi.CallbackAfterUserRegisterCommand, + Secret: req.Secret, + Users: req.Users, + } + + resp := &cbapi.CallbackBeforeUserRegisterResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + return err + } + return nil +} diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index f2ceb3beb..f4164dbf2 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -139,6 +139,9 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI for _, friendID := range friends { s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) } + if err := CallbackAfterUpdateUserInfo(ctx, req); err != nil { + return nil, err + } if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) } @@ -230,6 +233,9 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR if exist { return nil, errs.ErrRegisteredAlready.Wrap("userID registered already") } + if err := CallbackBeforeUserRegister(ctx, req); err != nil { + return nil, err + } now := time.Now() users := make([]*tablerelation.UserModel, 0, len(req.Users)) for _, user := range req.Users { @@ -246,6 +252,10 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR if err := s.Create(ctx, users); err != nil { return nil, err } + + if err := CallbackAfterUserRegister(ctx, req); err != nil { + return nil, err + } return resp, nil } diff --git a/pkg/callbackstruct/common.go b/pkg/callbackstruct/common.go index ef84d52b9..c58b9e415 100644 --- a/pkg/callbackstruct/common.go +++ b/pkg/callbackstruct/common.go @@ -14,8 +14,10 @@ package callbackstruct -import ( - "github.com/OpenIMSDK/tools/errs" +import "github.com/OpenIMSDK/tools/errs" + +const ( + Next = 1 ) type CommonCallbackReq struct { @@ -51,14 +53,15 @@ type CallbackResp interface { } type CommonCallbackResp struct { - ActionCode int `json:"actionCode"` + ActionCode int32 `json:"actionCode"` ErrCode int32 `json:"errCode"` ErrMsg string `json:"errMsg"` ErrDlt string `json:"errDlt"` + NextCode int32 `json:"nextCode"` } func (c CommonCallbackResp) Parse() error { - if c.ActionCode != errs.NoError || c.ErrCode != errs.NoError { + if c.ActionCode != errs.NoError || c.NextCode == Next { return errs.NewCodeError(int(c.ErrCode), c.ErrMsg).WithDetail(c.ErrDlt) } return nil diff --git a/pkg/callbackstruct/constant.go b/pkg/callbackstruct/constant.go new file mode 100644 index 000000000..f029e3713 --- /dev/null +++ b/pkg/callbackstruct/constant.go @@ -0,0 +1,33 @@ +package callbackstruct + +const ( + CallbackQuitGroupCommand = "callbackQuitGroupCommand" + CallbackKillGroupCommand = "callbackKillGroupCommand" + CallbackDisMissGroupCommand = "callbackDisMissGroupCommand" + CallbackBeforeJoinGroupCommand = "callbackBeforeJoinGroupCommand" + CallbackGroupMsgReadCommand = "callbackGroupMsgReadCommand" + CallbackMsgModifyCommand = "callbackMsgModifyCommand" + CallbackAfterUpdateUserInfoCommand = "callbackAfterUpdateUserInfoCommand" + CallbackBeforeUserRegisterCommand = "callbackBeforeUserRegisterCommand" + CallbackAfterUserRegisterCommand = "callbackAfterUserRegisterCommand" + CallbackTransferGroupOwnerAfter = "callbackTransferGroupOwnerAfter" + CallbackBeforeSetFriendRemark = "callbackBeforeSetFriendRemark" + CallbackAfterSetFriendRemark = "callbackAfterSetFriendRemark" + CallbackSingleMsgRead = "callbackSingleMsgRead" + CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand" + CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand" + CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand" + CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand" + CallbackUserOnlineCommand = "callbackUserOnlineCommand" + CallbackUserOfflineCommand = "callbackUserOfflineCommand" + CallbackUserKickOffCommand = "callbackUserKickOffCommand" + CallbackOfflinePushCommand = "callbackOfflinePushCommand" + CallbackOnlinePushCommand = "callbackOnlinePushCommand" + CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand" + CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand" + CallbackBeforeUpdateUserInfoCommand = "callbackBeforeUpdateUserInfoCommand" + CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand" + CallbackAfterCreateGroupCommand = "callbackAfterCreateGroupCommand" + CallbackBeforeMemberJoinGroupCommand = "callbackBeforeMemberJoinGroupCommand" + CallbackBeforeSetGroupMemberInfoCommand = "CallbackBeforeSetGroupMemberInfoCommand" +) diff --git a/pkg/callbackstruct/friend.go b/pkg/callbackstruct/friend.go index 7e89824e2..ebbd08b19 100644 --- a/pkg/callbackstruct/friend.go +++ b/pkg/callbackstruct/friend.go @@ -19,9 +19,52 @@ type CallbackBeforeAddFriendReq struct { FromUserID string `json:"fromUserID" ` ToUserID string `json:"toUserID"` ReqMsg string `json:"reqMsg"` - OperationID string `json:"operationID"` } type CallbackBeforeAddFriendResp struct { CommonCallbackResp } + +type CallBackAddFriendReplyBeforeReq struct { + CallbackCommand `json:"callbackCommand"` + FromUserID string `json:"fromUserID" ` + ToUserID string `json:"toUserID"` +} + +type CallBackAddFriendReplyBeforeResp struct { + CommonCallbackResp +} + +type CallbackAfterAddFriendReq struct { + CallbackCommand `json:"callbackCommand"` + FromUserID string `json:"fromUserID" ` + ToUserID string `json:"toUserID"` + ReqMsg string `json:"reqMsg"` +} + +type CallbackAfterAddFriendResp struct { + CommonCallbackResp +} + +type CallbackBeforeSetFriendRemarkReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID"` + FriendUserID string `json:"friendUserID"` + Remark string `json:"remark"` +} + +type CallbackBeforeSetFriendRemarkResp struct { + CommonCallbackResp + Remark string `json:"remark"` +} + +type CallbackAfterSetFriendRemarkReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID"` + FriendUserID string `json:"friendUserID"` + Remark string `json:"remark"` +} + +type CallbackAfterSetFriendRemarkResp struct { + CommonCallbackResp +} diff --git a/pkg/callbackstruct/group.go b/pkg/callbackstruct/group.go index 11b33bf0a..79e02ba0f 100644 --- a/pkg/callbackstruct/group.go +++ b/pkg/callbackstruct/group.go @@ -50,9 +50,18 @@ type CallbackBeforeCreateGroupResp struct { ApplyMemberFriend *int32 `json:"applyMemberFriend"` } +type CallbackAfterCreateGroupReq struct { + CallbackCommand `json:"callbackCommand"` + *common.GroupInfo + InitMemberList []*apistruct.GroupAddMemberInfo `json:"initMemberList"` +} + +type CallbackAfterCreateGroupResp struct { + CommonCallbackResp +} + type CallbackBeforeMemberJoinGroupReq struct { CallbackCommand `json:"callbackCommand"` - OperationID string `json:"operationID"` GroupID string `json:"groupID"` UserID string `json:"userID"` Ex string `json:"ex"` @@ -70,7 +79,6 @@ type CallbackBeforeMemberJoinGroupResp struct { type CallbackBeforeSetGroupMemberInfoReq struct { CallbackCommand `json:"callbackCommand"` - OperationID string `json:"operationID"` GroupID string `json:"groupID"` UserID string `json:"userID"` Nickname *string `json:"nickName"` @@ -86,3 +94,123 @@ type CallbackBeforeSetGroupMemberInfoResp struct { FaceURL *string `json:"faceURL"` RoleLevel *int32 `json:"roleLevel"` } + +type CallbackAfterSetGroupMemberInfoReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + UserID string `json:"userID"` + Nickname *string `json:"nickName"` + FaceURL *string `json:"faceURL"` + RoleLevel *int32 `json:"roleLevel"` + Ex *string `json:"ex"` +} + +type CallbackAfterSetGroupMemberInfoResp struct { + CommonCallbackResp +} + +type CallbackAfterGroupMemberExitReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + UserID string `json:"userID"` + GroupType *int32 `json:"groupType"` + ExitType string `json:"exitType"` +} + +type CallbackAfterGroupMemberExitResp struct { + CommonCallbackResp +} + +type CallbackAfterUngroupReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + GroupType *int32 `json:"groupType"` + OwnerID string `json:"ownerID"` + MemberList []string `json:"memberList"` +} + +type CallbackAfterUngroupResp struct { + CommonCallbackResp +} + +type CallbackAfterSetGroupInfoReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + GroupType *int32 `json:"groupType"` + UserID string `json:"userID"` + Name string `json:"name"` + Notification string `json:"notification"` + GroupUrl string `json:"groupUrl"` +} + +type CallbackAfterSetGroupInfoResp struct { + CommonCallbackResp +} + +type CallbackAfterRevokeMsgReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + GroupType *int32 `json:"groupType"` + UserID string `json:"userID"` + Content string `json:"content"` +} + +type CallbackAfterRevokeMsgResp struct { + CommonCallbackResp +} + +type CallbackQuitGroupReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + UserID string `json:"userID"` +} + +type CallbackQuitGroupResp struct { + CommonCallbackResp +} + +type CallbackKillGroupMemberReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + KickedUserIDs []string `json:"kickedUserIDs"` + Reason string `json:"reason"` +} + +type CallbackKillGroupMemberResp struct { + CommonCallbackResp +} + +type CallbackDisMissGroupReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + OwnerID string `json:"ownerID"` + GroupType string `json:"groupType"` + MembersID []string `json:"membersID"` +} + +type CallbackDisMissGroupResp struct { + CommonCallbackResp +} + +type CallbackJoinGroupReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + GroupType string `json:"groupType"` + ApplyID string `json:"applyID"` + ReqMessage string `json:"reqMessage"` +} + +type CallbackJoinGroupResp struct { + CommonCallbackResp +} + +type CallbackTransferGroupOwnerReq struct { + CallbackCommand `json:"callbackCommand"` + GroupID string `json:"groupID"` + OldOwnerUserID string `json:"oldOwnerUserID"` + NewOwnerUserID string `json:"newOwnerUserID"` +} + +type CallbackTransferGroupOwnerResp struct { + CommonCallbackResp +} diff --git a/pkg/callbackstruct/message.go b/pkg/callbackstruct/message.go index f404088e8..3adee618b 100644 --- a/pkg/callbackstruct/message.go +++ b/pkg/callbackstruct/message.go @@ -79,3 +79,46 @@ type CallbackMsgModifyCommandResp struct { AttachedInfo *string `json:"attachedInfo"` Ex *string `json:"ex"` } + +type CallbackSendGroupMsgErrorReq struct { + CommonCallbackReq + GroupID string `json:"groupID"` +} + +type CallbackSendGroupMsgErrorResp struct { + CommonCallbackResp +} + +type CallbackSingleMsgRevokeReq struct { + CallbackCommand `json:"callbackCommand"` + SendID string `json:"sendID"` + ReceiveID string `json:"receiveID"` + Content string `json:"content"` +} + +type CallbackSingleMsgRevokeResp struct { + CommonCallbackResp +} + +type CallbackGroupMsgReadReq struct { + CallbackCommand `json:"callbackCommand"` + SendID string `json:"sendID"` + ReceiveID string `json:"receiveID"` + UnreadMsgNum int64 `json:"unreadMsgNum"` + ContentType int64 `json:"contentType"` +} + +type CallbackGroupMsgReadResp struct { + CommonCallbackResp +} + +type CallbackSingleMsgReadReq struct { + CallbackCommand `json:"callbackCommand"` + SendID string `json:"sendID"` + ReceiveID string `json:"receiveID"` + ContentType int64 `json:"contentType"` +} + +type CallbackSingleMsgReadResp struct { + CommonCallbackResp +} diff --git a/pkg/callbackstruct/user.go b/pkg/callbackstruct/user.go index f01f4ca8a..f35cff554 100644 --- a/pkg/callbackstruct/user.go +++ b/pkg/callbackstruct/user.go @@ -14,9 +14,10 @@ package callbackstruct +import "github.com/OpenIMSDK/protocol/sdkws" + type CallbackBeforeUpdateUserInfoReq struct { CallbackCommand `json:"callbackCommand"` - OperationID string `json:"operationID"` UserID string `json:"userID"` Nickname *string `json:"nickName"` FaceURL *string `json:"faceURL"` @@ -28,3 +29,35 @@ type CallbackBeforeUpdateUserInfoResp struct { FaceURL *string `json:"faceURL"` Ex *string `json:"ex"` } + +type CallbackAfterUpdateUserInfoReq struct { + CallbackCommand `json:"callbackCommand"` + UserID string `json:"userID"` + Nickname string `json:"nickName"` + FaceURL string `json:"faceURL"` + Ex string `json:"ex"` +} +type CallbackAfterUpdateUserInfoResp struct { + CommonCallbackResp +} + +type CallbackBeforeUserRegisterReq struct { + CallbackCommand `json:"callbackCommand"` + Secret string `json:"secret"` + Users []*sdkws.UserInfo `json:"users"` +} + +type CallbackBeforeUserRegisterResp struct { + CommonCallbackResp + Users []*sdkws.UserInfo `json:"users"` +} + +type CallbackAfterUserRegisterReq struct { + CallbackCommand `json:"callbackCommand"` + Secret string `json:"secret"` + Users []*sdkws.UserInfo `json:"users"` +} + +type CallbackAfterUserRegisterResp struct { + CommonCallbackResp +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 1e9df7813..6d7658468 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -254,6 +254,8 @@ type configStruct struct { CallbackBeforeSendGroupMsg CallBackConfig `yaml:"beforeSendGroupMsg"` CallbackAfterSendGroupMsg CallBackConfig `yaml:"afterSendGroupMsg"` CallbackMsgModify CallBackConfig `yaml:"msgModify"` + CallbackSingleMsgRead CallBackConfig `yaml:"singleMsgRead"` + CallbackGroupMsgRead CallBackConfig `yaml:"groupMsgRead"` CallbackUserOnline CallBackConfig `yaml:"userOnline"` CallbackUserOffline CallBackConfig `yaml:"userOffline"` CallbackUserKickOff CallBackConfig `yaml:"userKickOff"` @@ -261,10 +263,21 @@ type configStruct struct { CallbackOnlinePush CallBackConfig `yaml:"onlinePush"` CallbackBeforeSuperGroupOnlinePush CallBackConfig `yaml:"superGroupOnlinePush"` CallbackBeforeAddFriend CallBackConfig `yaml:"beforeAddFriend"` + CallbackBeforeSetFriendRemark CallBackConfig `yaml:"callbackBeforeSetFriendRemark"` + CallbackAfterSetFriendRemark CallBackConfig `yaml:"callbackAfterSetFriendRemark"` CallbackBeforeUpdateUserInfo CallBackConfig `yaml:"beforeUpdateUserInfo"` + CallbackBeforeUserRegister CallBackConfig `yaml:"beforeUserRegister"` + CallbackAfterUpdateUserInfo CallBackConfig `yaml:"updateUserInfo"` + CallbackAfterUserRegister CallBackConfig `yaml:"afterUserRegister"` CallbackBeforeCreateGroup CallBackConfig `yaml:"beforeCreateGroup"` + CallbackAfterCreateGroup CallBackConfig `yaml:"afterCreateGroup"` CallbackBeforeMemberJoinGroup CallBackConfig `yaml:"beforeMemberJoinGroup"` CallbackBeforeSetGroupMemberInfo CallBackConfig `yaml:"beforeSetGroupMemberInfo"` + CallbackQuitGroup CallBackConfig `yaml:"quitGroup"` + CallbackKillGroupMember CallBackConfig `yaml:"killGroupMember"` + CallbackDismissGroup CallBackConfig `yaml:"dismissGroup"` + CallbackBeforeJoinGroup CallBackConfig `yaml:"joinGroup"` + CallbackTransferGroupOwnerAfter CallBackConfig `yaml:"transferGroupOwner"` } `yaml:"callback"` Prometheus struct { diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go index e0cedf357..f0fde3099 100644 --- a/pkg/common/http/http_client.go +++ b/pkg/common/http/http_client.go @@ -20,7 +20,6 @@ import ( "encoding/json" "io" "net/http" - urllib "net/url" "time" "github.com/OpenIMSDK/protocol/constant" @@ -107,17 +106,18 @@ func PostReturn(ctx context.Context, url string, header map[string]string, input } func callBackPostReturn(ctx context.Context, url, command string, input interface{}, output callbackstruct.CallbackResp, callbackConfig config.CallBackConfig) error { - defer log.ZDebug(ctx, "callback", "url", url, "command", command, "input", input, "callbackConfig", callbackConfig) - - v := urllib.Values{} - v.Set(constant.CallbackCommand, command) - url = url + "?" + v.Encode() + defer log.ZDebug(ctx, "callback", "url", url, "command", command, "input", input, "output", output, "callbackConfig", callbackConfig) + // + //v := urllib.Values{} + //v.Set(constant.CallbackCommand, command) + //url = url + "/" + v.Encode() + url = url + "/" + command b, err := Post(ctx, url, nil, input, callbackConfig.CallbackTimeOut) if err != nil { if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { log.ZWarn(ctx, "callback failed but continue", err, "url", url) - return errs.ErrCallbackContinue + return nil } return errs.ErrNetwork.Wrap(err.Error()) } @@ -125,7 +125,7 @@ func callBackPostReturn(ctx context.Context, url, command string, input interfac if err = json.Unmarshal(b, output); err != nil { if callbackConfig.CallbackFailedContinue != nil && *callbackConfig.CallbackFailedContinue { log.ZWarn(ctx, "callback failed but continue", err, "url", url) - return errs.ErrCallbackContinue + return nil } return errs.ErrData.Wrap(err.Error()) } diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index 6a87b44a6..aa4141a7d 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -376,6 +376,10 @@ def "FRIEND_VERIFY" "false" # 朋友验证 def "IOS_PUSH_SOUND" "xxx" # IOS推送声音 def "IOS_BADGE_COUNT" "true" # IOS徽章计数 def "IOS_PRODUCTION" "false" # IOS生产 +# callback 配置 +def "CALLBACK_ENABLE" "true" # 是否开启 Callback +def "CALLBACK_TIMEOUT" "5" # 最长超时时间 +def "CALLBACK_FAILED_CONTINUE" "true" # 失败后是否继续 ###################### Prometheus 配置信息 ###################### # 是否启用 Prometheus From ceb669dfb8ca68c5dfa295cf09b3c247dd5dfc2f Mon Sep 17 00:00:00 2001 From: xuexihuang <1339326187@qq.com> Date: Wed, 29 Nov 2023 10:41:11 +0800 Subject: [PATCH 10/18] Feature middleware (#1476) * fix:fix error values&logs * modify: add logs * feature:add redis io retry logic * feature:add redis error alert rule * test:for test alert * fix:fix prometheus rules * del:del test code --------- Co-authored-by: lin.huang --- config/instance-down-rules.yml | 13 +++- internal/msgtransfer/init.go | 7 +-- .../msgtransfer/online_history_msg_handler.go | 16 ++--- internal/rpc/msg/sync_msg.go | 12 +--- pkg/common/db/cache/msg.go | 31 +++++++++- pkg/common/db/controller/msg.go | 60 +++++++++---------- 6 files changed, 82 insertions(+), 57 deletions(-) diff --git a/config/instance-down-rules.yml b/config/instance-down-rules.yml index 72b1f5aa3..5541d2c54 100644 --- a/config/instance-down-rules.yml +++ b/config/instance-down-rules.yml @@ -8,4 +8,15 @@ groups: severity: critical annotations: summary: "Instance {{ $labels.instance }} down" - description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes." \ No newline at end of file + description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes." + + - name: database_insert_failure_alerts + rules: + - alert: DatabaseInsertFailed + expr: (increase(msg_insert_redis_failed_total[5m]) > 0) or (increase(msg_insert_mongo_failed_total[5m]) > 0) + for: 1m + labels: + severity: critical + annotations: + summary: "Increase in MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter detected" + description: "Either MsgInsertRedisFailedCounter or MsgInsertMongoFailedCounter has increased in the last 5 minutes, indicating failures in message insert operations to Redis or MongoDB,maybe the redis or mongodb is crash." diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 4ce015543..8436317ee 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -17,16 +17,15 @@ package msgtransfer import ( "errors" "fmt" - "log" - "net/http" - "sync" - "github.com/OpenIMSDK/tools/mw" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "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/db/cache" diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index b019b0120..eb8e500fe 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -252,7 +252,10 @@ func (och *OnlineHistoryRedisConsumerHandler) handleNotification( return } log.ZDebug(ctx, "success to next topic", "conversationID", conversationID) - och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) + err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) + if err != nil { + log.ZError(ctx, "MsgToMongoMQ error", err) + } och.toPushTopic(ctx, key, conversationID, storageList) } } @@ -277,9 +280,6 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg( lastSeq, isNewConversation, err := och.msgDatabase.BatchInsertChat2Cache(ctx, conversationID, storageList) if err != nil && errs.Unwrap(err) != redis.Nil { log.ZError(ctx, "batch data insert to redis err", err, "storageMsgList", storageList) - och.singleMsgFailedCountMutex.Lock() - och.singleMsgFailedCount += uint64(len(storageList)) - och.singleMsgFailedCountMutex.Unlock() return } if isNewConversation { @@ -311,10 +311,10 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg( } log.ZDebug(ctx, "success incr to next topic") - och.singleMsgSuccessCountMutex.Lock() - och.singleMsgSuccessCount += uint64(len(storageList)) - och.singleMsgSuccessCountMutex.Unlock() - och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) + err = och.msgDatabase.MsgToMongoMQ(ctx, key, conversationID, storageList, lastSeq) + if err != nil { + log.ZError(ctx, "MsgToMongoMQ error", err) + } och.toPushTopic(ctx, key, conversationID, storageList) } } diff --git a/internal/rpc/msg/sync_msg.go b/internal/rpc/msg/sync_msg.go index 7c67ff05f..dbd8da4d8 100644 --- a/internal/rpc/msg/sync_msg.go +++ b/internal/rpc/msg/sync_msg.go @@ -42,15 +42,8 @@ func (m *msgServer) PullMessageBySeqs( log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID) continue } - minSeq, maxSeq, msgs, err := m.MsgDatabase.GetMsgBySeqsRange( - ctx, - req.UserID, - seq.ConversationID, - seq.Begin, - seq.End, - seq.Num, - conversation.MaxSeq, - ) + minSeq, maxSeq, msgs, err := m.MsgDatabase.GetMsgBySeqsRange(ctx, req.UserID, seq.ConversationID, + seq.Begin, seq.End, seq.Num, conversation.MaxSeq) if err != nil { log.ZWarn(ctx, "GetMsgBySeqsRange error", err, "conversationID", seq.ConversationID, "seq", seq) continue @@ -64,7 +57,6 @@ func (m *msgServer) PullMessageBySeqs( } if len(msgs) == 0 { log.ZWarn(ctx, "not have msgs", nil, "conversationID", seq.ConversationID, "seq", seq) - continue } resp.Msgs[seq.ConversationID] = &sdkws.PullMsgs{Msgs: msgs, IsEnd: isEnd} diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 282d1d1c1..f86b44d9b 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -173,7 +173,20 @@ 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 { - return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey) + var retErr error + 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) { @@ -181,7 +194,21 @@ func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m } func (c *msgCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) { - return c.getSeq(ctx, conversationID, c.getMaxSeqKey) + var retErr error + 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 { diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index fb0a9c702..cba0a6bbd 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -357,7 +357,9 @@ 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) { - currentMaxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) + cancelCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) + defer cancel() + currentMaxSeq, err := db.cache.GetMaxSeq(cancelCtx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { log.ZError(ctx, "db.cache.GetMaxSeq", err) return 0, false, err @@ -384,19 +386,21 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum)) log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID) } else { - prommetrics.MsgInsertRedisSuccessCounter.Inc() + prommetrics.MsgInsertRedisSuccessCounter.Add(float64(len(msgs))) } - err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq) + cancelCtx, cancel = context.WithTimeout(ctx, 1*time.Minute) + defer cancel() + err = db.cache.SetMaxSeq(cancelCtx, conversationID, currentMaxSeq) if err != nil { log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) - if err != nil { + if err2 != nil { log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } - return lastMaxSeq, isNew, utils.Wrap(err, "") + return lastMaxSeq, isNew, errs.Wrap(err, "redis SetMaxSeq error") } func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) { @@ -654,16 +658,26 @@ 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) { userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) - if err != nil && errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err + if err != nil { + log.ZError(ctx, "cache.GetConversationUserMinSeq error", err) + if errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err + } } minSeq, err := db.cache.GetMinSeq(ctx, conversationID) - if err != nil && errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err + if err != nil { + log.ZError(ctx, "cache.GetMinSeq error", err) + if errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err + } } maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) - if err != nil && errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err + if err != nil { + log.ZError(ctx, "cache.GetMaxSeq error", err) + if errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err + } + } if userMinSeq < minSeq { minSeq = userMinSeq @@ -676,34 +690,16 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co } successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs) if err != nil { - if err != redis.Nil { - log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID) - } + 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", - len(successMsgs), - "failedSeqs", - failedSeqs, - "conversationID", - conversationID, - ) + log.ZInfo(ctx, "db.cache.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs", seqs, "successMsgs", + len(successMsgs), "failedSeqs", failedSeqs, "conversationID", conversationID) if len(failedSeqs) > 0 { mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs) if err != nil { - return 0, 0, nil, err } - successMsgs = append(successMsgs, mongoMsgs...) } return minSeq, maxSeq, successMsgs, nil From 4c7e0295bf34b292b5baea785a6edb07ec53b6a1 Mon Sep 17 00:00:00 2001 From: healingtjx <33712699+healingtjx@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:41:47 +0800 Subject: [PATCH 11/18] feat: OpenIMServer compatible qiniu kodo (#1460) * build : add aws and kodo dependency * feat: add qiniu kodo * Doc : Add Qiniu Cloud Kodo Document and Config --- config/config.yaml | 9 +- deployments/templates/openim.yaml | 8 + docs/contrib/environment.md | 16 ++ go.mod | 19 ++ go.sum | 65 ++++++ internal/rpc/third/third.go | 5 +- pkg/common/config/config.go | 9 + pkg/common/db/s3/kodo/internal.go | 1 + pkg/common/db/s3/kodo/kodo.go | 323 ++++++++++++++++++++++++++++++ scripts/install/environment.sh | 9 + 10 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 pkg/common/db/s3/kodo/internal.go create mode 100644 pkg/common/db/s3/kodo/kodo.go diff --git a/config/config.yaml b/config/config.yaml index d66f15704..e8995c82b 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -158,7 +158,14 @@ object: accessKeySecret: '' sessionToken: '' publicRead: false - + kodo: + endpoint: "http://s3.cn-east-1.qiniucs.com" + bucket: "demo-9999999" + bucketURL: "http://your.domain.com" + accessKeyID: '' + accessKeySecret: '' + sessionToken: '' + publicRead: false ###################### RPC Port Configuration ###################### # RPC service ports # These ports are passed into the program by the script and are not recommended to modify diff --git a/deployments/templates/openim.yaml b/deployments/templates/openim.yaml index c0e552c24..fde05e86e 100644 --- a/deployments/templates/openim.yaml +++ b/deployments/templates/openim.yaml @@ -158,6 +158,14 @@ object: accessKeySecret: ${OSS_ACCESS_KEY_SECRET} sessionToken: ${OSS_SESSION_TOKEN} publicRead: ${OSS_PUBLIC_READ} + kodo: + endpoint: "${KODO_ENDPOINT}" + bucket: "${KODO_BUCKET}" + bucketURL: "${KODO_BUCKET_URL}" + accessKeyID: ${KODO_ACCESS_KEY_ID} + accessKeySecret: ${KODO_ACCESS_KEY_SECRET} + sessionToken: ${KODO_SESSION_TOKEN} + publicRead: ${KODO_PUBLIC_READ} ###################### RPC Port Configuration ###################### # RPC service ports diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index 8e0cf2572..6450549e7 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -37,6 +37,7 @@ * 2.20. [Prometheus Configuration](#PrometheusConfiguration-1) * 2.20.1. [General Configuration](#GeneralConfiguration) * 2.20.2. [Service-Specific Prometheus Ports](#Service-SpecificPrometheusPorts) + * 2.21. [Qiniu Cloud Kodo Configuration](#QiniuCloudKODOConfiguration) ## 0. OpenIM Config File @@ -528,3 +529,18 @@ This section involves configuring Prometheus, including enabling/disabling it an | RTC Service | `RTC_PROM_PORT` | '21300' | Prometheus port for the RTC service. | | Third Service | `THIRD_PROM_PORT` | '21301' | Prometheus port for the Third service. | | Message Transfer Service | `MSG_TRANSFER_PROM_PORT` | '21400, 21401, 21402, 21403' | Prometheus ports for the Message Transfer service. | + + +### 2.21. Qiniu Cloud Kodo Configuration + +This section involves setting up Qiniu Cloud Kodo, including its endpoint, bucket name, and credentials. + +| Parameter | Example Value | Description | +| --------------------- | ------------------------------------------------------------ | ---------------------------------------- | +| KODO_ENDPOINT | "[http://s3.cn-east-1.qiniucs.com](http://s3.cn-east-1.qiniucs.com)" | Endpoint URL for Qiniu Cloud Kodo. | +| KODO_BUCKET | "demo-9999999" | Bucket name for Qiniu Cloud Kodo. | +| KODO_BUCKET_URL | "[http://your.domain.com](http://your.domain.com)" | Bucket URL for Qiniu Cloud Kodo. | +| KODO_ACCESS_KEY_ID | [User Defined] | Access key ID for Qiniu Cloud Kodo. | +| KODO_ACCESS_KEY_SECRET | [User Defined] | Access key secret for Qiniu Cloud Kodo. | +| KODO_SESSION_TOKEN | [User Defined] | Session token for Qiniu Cloud Kodo. | +| KODO_PUBLIC_READ | "false" | Public read access. | diff --git a/go.mod b/go.mod index e7d9097d2..fc7c615c6 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,24 @@ require ( cloud.google.com/go/iam v1.1.2 // indirect cloud.google.com/go/longrunning v0.5.1 // indirect cloud.google.com/go/storage v1.30.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.23.1 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.25.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.17.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.25.4 // indirect + github.com/aws/smithy-go v1.17.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -115,6 +133,7 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect + github.com/qiniu/go-sdk/v7 v7.18.2 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect github.com/sergi/go-diff v1.0.0 // indirect diff --git a/go.sum b/go.sum index b1ee37912..10cb9ee8c 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,42 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aws/aws-sdk-go-v2 v1.23.1 h1:qXaFsOOMA+HsZtX8WoCa+gJnbyW7qyFFBlPqvTSzbaI= +github.com/aws/aws-sdk-go-v2 v1.23.1/go.mod h1:i1XDttT4rnf6vxc9AuskLc6s7XBee8rlLilKlc03uAA= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 h1:ZY3108YtBNq96jNZTICHxN1gSBSbnvIdYwwqnvCV4Mc= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1/go.mod h1:t8PYl/6LzdAqsU4/9tz28V/kU+asFePvpOMkdul0gEQ= +github.com/aws/aws-sdk-go-v2/config v1.25.4 h1:r+X1x8QI6FEPdJDWCNBDZHyAcyFwSjHN8q8uuus+Axs= +github.com/aws/aws-sdk-go-v2/config v1.25.4/go.mod h1:8GTjImECskr7D88P/Nn9uM4M4rLY9i77hLJZgkZEWV8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.3 h1:8PeI2krzzjDJ5etmgaMiD1JswsrLrWvKKu/uBUtNy1g= +github.com/aws/aws-sdk-go-v2/credentials v1.16.3/go.mod h1:Kdh/okh+//vQ/AjEt81CjvkTo64+/zIE4OewP7RpfXk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5 h1:KehRNiVzIfAcj6gw98zotVbb/K67taJE0fkfgM6vzqU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.5/go.mod h1:VhnExhw6uXy9QzetvpXDolo1/hjhx4u9qukBGkuUwjs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4 h1:LAm3Ycm9HJfbSCd5I+wqC2S9Ej7FPrgr5CQoOljJZcE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.4/go.mod h1:xEhvbJcyUf/31yfGSQBe01fukXwXJ0gxDp7rLfymWE0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4 h1:4GV0kKZzUxiWxSVpn/9gwR0g21NF1Jsyduzo9rHgC/Q= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.4/go.mod h1:dYvTNAggxDZy6y1AF7YDwXsPuHFy/VNEpEI/2dWK9IU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4 h1:40Q4X5ebZruRtknEZH/bg91sT5pR853F7/1X9QRbI54= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.4/go.mod h1:u77N7eEECzUv7F0xl2gcfK/vzc8wcjWobpy+DcrLJ5E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 h1:rpkF4n0CyFcrJUG/rNNohoTmhtWlFTRI4BsZOh9PvLs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1/go.mod h1:l9ymW25HOqymeU2m1gbUQ3rUIsTwKs8gYHXkqDQUhiI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4 h1:6DRKQc+9cChgzL5gplRGusI5dBGeiEod4m/pmGbcX48= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.4/go.mod h1:s8ORvrW4g4v7IvYKIAoBg17w3GQ+XuwXDXYrQ5SkzU0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4 h1:rdovz3rEu0vZKbzoMYPTehp0E8veoE9AyfzqCr5Eeao= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.4/go.mod h1:aYCGNjyUCUelhofxlZyj63srdxWUSsBSGg5l6MCuXuE= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4 h1:o3DcfCxGDIT20pTbVKVhp3vWXOj/VvgazNJvumWeYW0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.4/go.mod h1:Uy0KVOxuTK2ne+/PKQ+VvEeWmjMMksE17k/2RK/r5oM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1 h1:1w11lfXOa8HoHoSlNtt4mqv/N3HmDOa+OnUH3Y9DHm8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.43.1/go.mod h1:dqJ5JBL0clzgHriH35Amx3LRFY6wNIPUX7QO/BerSBo= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.3 h1:CdsSOGlFF3Pn+koXOIpTtvX7st0IuGsZ8kJqcWMlX54= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.3/go.mod h1:oA6VjNsLll2eVuUoF2D+CMyORgNzPEW/3PyUdq6WQjI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1 h1:cbRqFTVnJV+KRpwFl76GJdIZJKKCdTPnjUZ7uWh3pIU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.1/go.mod h1:hHL974p5auvXlZPIjJTblXJpbkfK4klBczlsEaMCGVY= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.4 h1:yEvZ4neOQ/KpUqyR+X0ycUTW/kVRNR4nDZ38wStHGAA= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.4/go.mod h1:feTnm2Tk/pJxdX+eooEsxvlvTWBvDm6CasRZ+JOs2IY= +github.com/aws/smithy-go v1.17.0 h1:wWJD7LX6PBV6etBUwO0zElG0nWN9rUhp0WdYeHSHAaI= +github.com/aws/smithy-go v1.17.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -56,6 +92,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -91,11 +128,17 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= @@ -214,11 +257,15 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -275,6 +322,7 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -290,12 +338,18 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= +github.com/qiniu/go-sdk/v7 v7.18.2 h1:vk9eo5OO7aqgAOPF0Ytik/gt7CMKuNgzC/IPkhda6rk= +github.com/qiniu/go-sdk/v7 v7.18.2/go.mod h1:nqoYCNo53ZlGA521RvRethvxUDvXKt4gtYXOwye868w= +github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -318,6 +372,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -368,8 +423,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= @@ -400,6 +457,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= @@ -432,16 +490,19 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -450,6 +511,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -510,6 +572,8 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -529,6 +593,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index b48eddea9..eed3d4802 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,14 +17,15 @@ package third import ( "context" "fmt" + "net/url" "time" "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/kodo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" - "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/third" @@ -72,6 +73,8 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e o, err = cos.NewCos() case "oss": o, err = oss.NewOSS() + case "kodo": + o, err = kodo.NewKodo() default: err = fmt.Errorf("invalid object enable: %s", enable) } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 6d7658468..d8bee6af8 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -153,6 +153,15 @@ type configStruct struct { SessionToken string `yaml:"sessionToken"` PublicRead bool `yaml:"publicRead"` } `yaml:"oss"` + Kodo struct { + Endpoint string `yaml:"endpoint"` + Bucket string `yaml:"bucket"` + BucketURL string `yaml:"bucketURL"` + AccessKeyID string `yaml:"accessKeyID"` + AccessKeySecret string `yaml:"accessKeySecret"` + SessionToken string `yaml:"sessionToken"` + PublicRead bool `yaml:"publicRead"` + } `yaml:"kodo"` } `yaml:"object"` RpcPort struct { diff --git a/pkg/common/db/s3/kodo/internal.go b/pkg/common/db/s3/kodo/internal.go new file mode 100644 index 000000000..3a4943e62 --- /dev/null +++ b/pkg/common/db/s3/kodo/internal.go @@ -0,0 +1 @@ +package kodo diff --git a/pkg/common/db/s3/kodo/kodo.go b/pkg/common/db/s3/kodo/kodo.go new file mode 100644 index 000000000..d73220b3b --- /dev/null +++ b/pkg/common/db/s3/kodo/kodo.go @@ -0,0 +1,323 @@ +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 +} diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index aa4141a7d..98636bbde 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -223,6 +223,15 @@ def "OSS_ACCESS_KEY_SECRET" # 阿里 def "OSS_SESSION_TOKEN" # 阿里云OSS的会话令牌 def "OSS_PUBLIC_READ" "false" # 公有读 +#七牛云配置信息 +def "KODO_ENDPOINT" "http://s3.cn-east-1.qiniucs.com" # 七牛云OSS的端点URL +def "KODO_BUCKET" "demo-9999999" # 七牛云OSS的存储桶名称 +def "KODO_BUCKET_URL" "http://your.domain.com" # 七牛云OSS的存储桶URL +def "KODO_ACCESS_KEY_ID" # 七牛云OSS的访问密钥ID +def "KODO_ACCESS_KEY_SECRET" # 七牛云OSS的密钥 +def "KODO_SESSION_TOKEN" # 七牛云OSS的会话令牌 +def "KODO_PUBLIC_READ" "false" # 公有读 + ###################### Redis 配置信息 ###################### def "REDIS_PORT" "16379" # Redis的端口 def "REDIS_ADDRESS" "${DOCKER_BRIDGE_GATEWAY}" # Redis的地址 From 35bac04f582875f67dfba5ead156897a814dcd63 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Wed, 29 Nov 2023 10:44:37 +0800 Subject: [PATCH 12/18] fix: grace shutdown for gw (#1478) Signed-off-by: rfyiamcool --- internal/msggateway/init.go | 21 +++++++++--- internal/msggateway/n_ws_server.go | 49 +++++++++++++++++++++++--- pkg/common/cmd/msg_gateway.go | 19 +++++++---- pkg/common/startrpc/start.go | 55 ++++++++++++++++++++++++++---- 4 files changed, 121 insertions(+), 23 deletions(-) diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go index 14c320c42..aeba0a24a 100644 --- a/internal/msggateway/init.go +++ b/internal/msggateway/init.go @@ -19,6 +19,7 @@ import ( "time" "github.com/OpenIMSDK/tools/utils" + "golang.org/x/sync/errgroup" "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -43,12 +44,22 @@ func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { if err != nil { return err } + hubServer := NewServer(rpcPort, prometheusPort, longServer) - go func() { - err := hubServer.Start() + + wg := errgroup.Group{} + wg.Go(func() error { + err = hubServer.Start() if err != nil { - panic(utils.Wrap1(err)) + return utils.Wrap1(err) } - }() - return hubServer.LongConnServer.Run() + return err + }) + + wg.Go(func() error { + return hubServer.LongConnServer.Run() + }) + + err = wg.Wait() + return err } diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index a249ff70f..99a7a4805 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -18,9 +18,12 @@ import ( "context" "errors" "net/http" + "os" + "os/signal" "strconv" "sync" "sync/atomic" + "syscall" "time" "github.com/go-playground/validator/v10" @@ -156,10 +159,22 @@ func NewWsServer(opts ...Option) (*WsServer, error) { } func (ws *WsServer) Run() error { - var client *Client - go func() { + var ( + client *Client + wg errgroup.Group + + sigs = make(chan os.Signal, 1) + done = make(chan struct{}, 1) + ) + + server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil} + + wg.Go(func() error { for { select { + case <-done: + return nil + case client = <-ws.registerChan: ws.registerClient(client) case client = <-ws.unregisterChan: @@ -168,10 +183,34 @@ func (ws *WsServer) Run() error { ws.multiTerminalLoginChecker(onlineInfo.clientOK, onlineInfo.oldClients, onlineInfo.newClient) } } + }) + + wg.Go(func() error { + http.HandleFunc("/", ws.wsHandler) + return server.ListenAndServe() + }) + + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + <-sigs + + go func() { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + // graceful exit operation for server + _ = server.Shutdown(ctx) + _ = wg.Wait() + close(done) }() - http.HandleFunc("/", ws.wsHandler) - // http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {}) - return http.ListenAndServe(":"+utils.IntToString(ws.port), nil) // Start listening + + select { + case <-done: + return nil + + case <-time.After(15 * time.Second): + return utils.Wrap1(errors.New("timeout exit")) + } + } var concurrentRequest = 3 diff --git a/pkg/common/cmd/msg_gateway.go b/pkg/common/cmd/msg_gateway.go index 7f0abb771..25fcc1177 100644 --- a/pkg/common/cmd/msg_gateway.go +++ b/pkg/common/cmd/msg_gateway.go @@ -17,12 +17,12 @@ package cmd import ( "log" - "github.com/openimsdk/open-im-server/v3/internal/msggateway" - v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/spf13/cobra" "github.com/OpenIMSDK/protocol/constant" + + "github.com/openimsdk/open-im-server/v3/internal/msggateway" + v3config "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) type MsgGatewayCmd struct { @@ -60,14 +60,19 @@ func (m *MsgGatewayCmd) Exec() error { m.addRunE() return m.Execute() } + func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int { - if portType == constant.FlagWsPort { + switch portType { + case constant.FlagWsPort: return v3config.Config.LongConnSvr.OpenImWsPort[0] - } else if portType == constant.FlagPort { + + case constant.FlagPort: return v3config.Config.LongConnSvr.OpenImMessageGatewayPort[0] - } else if portType == constant.FlagPrometheusPort { + + case constant.FlagPrometheusPort: return v3config.Config.Prometheus.MessageGatewayPrometheusPort[0] - } else { + + default: return 0 } } diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index d5e31701e..01076bbbb 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -15,14 +15,21 @@ package startrpc import ( + "errors" "fmt" "log" "net" "net/http" + "os" + "os/signal" "strconv" + "sync" + "syscall" + "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "golang.org/x/sync/errgroup" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" @@ -56,31 +63,37 @@ func Start( if err != nil { return err } + defer listener.Close() client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { return utils.Wrap1(err) } + defer client.Close() client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) registerIP, err := network.GetRpcRegisterIP(config.Config.Rpc.RegisterIP) if err != nil { return err } + var reg *prometheus.Registry var metric *grpcprometheus.ServerMetrics - // ctx 中间件 if config.Config.Prometheus.Enable { - ////////////////////////// cusMetrics := prommetrics.GetGrpcCusMetrics(rpcRegisterName) - reg, metric, err = prommetrics.NewGrpcPromObj(cusMetrics) + reg, metric, _ = prommetrics.NewGrpcPromObj(cusMetrics) options = append(options, mw.GrpcServer(), grpc.StreamInterceptor(metric.StreamServerInterceptor()), grpc.UnaryInterceptor(metric.UnaryServerInterceptor())) } else { options = append(options, mw.GrpcServer()) } + srv := grpc.NewServer(options...) - defer srv.GracefulStop() + once := sync.Once{} + defer func() { + once.Do(srv.GracefulStop) + }() + err = rpcFn(client, srv) if err != nil { return utils.Wrap1(err) @@ -94,7 +107,10 @@ func Start( if err != nil { return utils.Wrap1(err) } - go func() { + + var wg errgroup.Group + + wg.Go(func() error { if config.Config.Prometheus.Enable && prometheusPort != 0 { metric.InitializeMetrics(srv) // Create a HTTP server for prometheus. @@ -103,7 +119,34 @@ func Start( log.Fatal("Unable to start a http server.") } } + return nil + }) + + wg.Go(func() error { + return utils.Wrap1(srv.Serve(listener)) + }) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + <-sigs + + var ( + done = make(chan struct{}, 1) + gerr error + ) + + go func() { + once.Do(srv.GracefulStop) + gerr = wg.Wait() + close(done) }() - return utils.Wrap1(srv.Serve(listener)) + select { + case <-done: + return gerr + + case <-time.After(15 * time.Second): + return utils.Wrap1(errors.New("timeout exit")) + } + } From 0efc235f45377d997d283557b1f61acf922f9ab3 Mon Sep 17 00:00:00 2001 From: AndrewZuo01 <59896149+AndrewZuo01@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:10:48 +0800 Subject: [PATCH 13/18] add webhooks (#1465) * add callback before join group * fix bug * fix deployments/templates/alertmanager.yml * fix bug * update callback after join group * merge callback after join group * update callback setrgoup info * test * test * test * update three functions in friend category * test friend and blacklist * test * test * test * Update openim.yaml * merge callback after join group * merge callback after join group * merge callback after join group * fix callbackbeforesetgroupinfo * fix eventtime * update api request required * update api request required * update api request required * delete unused code * delete unused code * fix * Update .env * Update .env * Update callback.go * Update callback.go * Update .env * Update .env * fix: merge * update * fix: merge * fix: fix bugs * update callback enable * update callback enable * update callback enable * update callback enable * update callback enable * update callback enable * Update openim.yaml * Update environment.sh * Update environment.md * Update environment.md * Update environment.sh --------- Co-authored-by: Gordon <1432970085@qq.com> --- .env | 11 +- cmd/openim-msggateway/main.go | 1 + config/alertmanager.yml | 2 +- config/config.yaml | 4 + deployments/templates/alertmanager.yml | 4 +- deployments/templates/openim.yaml | 67 ++++++++++- docs/contrib/environment.md | 2 +- go.mod | 2 +- go.sum | 4 +- internal/api/msg.go | 14 +-- internal/msggateway/n_ws_server.go | 1 + internal/rpc/friend/black.go | 6 + internal/rpc/friend/callback.go | 117 ++++++++++++++++++- internal/rpc/friend/friend.go | 18 ++- internal/rpc/group/callback.go | 156 ++++++++++++++++++++++++- internal/rpc/group/group.go | 18 +++ internal/rpc/msg/callback.go | 26 ++++- internal/rpc/msg/revoke.go | 4 + internal/rpc/user/callback.go | 4 +- pkg/apistruct/msg.go | 73 ++++++------ pkg/callbackstruct/constant.go | 18 ++- pkg/callbackstruct/friend.go | 77 ++++++++++-- pkg/callbackstruct/group.go | 117 +++++++++++-------- pkg/callbackstruct/message.go | 20 ---- pkg/callbackstruct/revoke.go | 11 ++ pkg/common/config/config.go | 15 ++- scripts/install/environment.sh | 3 +- 27 files changed, 642 insertions(+), 153 deletions(-) create mode 100644 pkg/callbackstruct/revoke.go diff --git a/.env b/.env index ae76a0440..8213b9e3c 100644 --- a/.env +++ b/.env @@ -94,7 +94,7 @@ OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10 # Address or hostname for the Prometheus network. # Default: PROMETHEUS_NETWORK_ADDRESS=172.28.0.11 PROMETHEUS_NETWORK_ADDRESS=172.28.0.11 - + # Address or hostname for the Grafana network. # Default: GRAFANA_NETWORK_ADDRESS=172.28.0.12 GRAFANA_NETWORK_ADDRESS=172.28.0.12 @@ -106,7 +106,10 @@ NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.13 # Address or hostname for the OpenIM admin network. # Default: OPENIM_ADMIN_NETWORK_ADDRESS=172.28.0.14 OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=172.28.0.14 - + +# Address or hostname for the alertmanager network. +# Default: ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 +ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 # =============================================== # = Component Extension Configuration = # =============================================== @@ -306,3 +309,7 @@ GRAFANA_PORT=3000 # Port for the admin front. # Default: OPENIM_ADMIN_FRONT_PORT=11002 OPENIM_ADMIN_FRONT_PORT=11002 + +# Port for the alertmanager. +# Default: ALERT_MANAGER_PORT=19093 +ALERT_MANAGER_PORT=19093 diff --git a/cmd/openim-msggateway/main.go b/cmd/openim-msggateway/main.go index f6870694b..6d212e467 100644 --- a/cmd/openim-msggateway/main.go +++ b/cmd/openim-msggateway/main.go @@ -23,6 +23,7 @@ func main() { msgGatewayCmd.AddWsPortFlag() msgGatewayCmd.AddPortFlag() msgGatewayCmd.AddPrometheusPortFlag() + if err := msgGatewayCmd.Exec(); err != nil { panic(err.Error()) } diff --git a/config/alertmanager.yml b/config/alertmanager.yml index 71cdd2b8f..ee14b6464 100644 --- a/config/alertmanager.yml +++ b/config/alertmanager.yml @@ -26,7 +26,7 @@ route: receivers: - name: email email_configs: - - to: {EMAIL_TO:-'alert@example.com'} + - to: '{EMAIL_TO:-'alert@example.com'}' html: '{{ template "email.to.html" . }}' headers: { Subject: "[OPENIM-SERVER]Alarm" } send_resolved: true diff --git a/config/config.yaml b/config/config.yaml index e8995c82b..b17d10073 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -375,6 +375,10 @@ callback: enable: false timeout: 5 failedContinue: true + beforeInviteUserToGroup: + enable: true + timeout: 5 + failedContinue: true beforeSetGroupMemberInfo: enable: false timeout: 5 diff --git a/deployments/templates/alertmanager.yml b/deployments/templates/alertmanager.yml index 47090f148..ea99a9286 100644 --- a/deployments/templates/alertmanager.yml +++ b/deployments/templates/alertmanager.yml @@ -27,7 +27,7 @@ route: receivers: - name: email email_configs: - - to: ${ALERTMANAGER_EMAIL_TO} + - to: '${ALERTMANAGER_EMAIL_TO}' html: '{{ template "email.to.html" . }}' headers: { Subject: "[OPENIM-SERVER]Alarm" } - send_resolved: true \ No newline at end of file + send_resolved: true diff --git a/deployments/templates/openim.yaml b/deployments/templates/openim.yaml index fde05e86e..fc90bfc2f 100644 --- a/deployments/templates/openim.yaml +++ b/deployments/templates/openim.yaml @@ -320,7 +320,7 @@ iosPush: # Timeout in seconds # Whether to continue execution if callback fails callback: - url: + url: "" beforeSendSingleMsg: enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} @@ -389,6 +389,10 @@ callback: enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterSetGroupMemberInfo: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} setMessageReactionExtensions: enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} @@ -441,7 +445,66 @@ callback: enable: ${CALLBACK_ENABLE} timeout: ${CALLBACK_TIMEOUT} failedContinue: ${CALLBACK_FAILED_CONTINUE} - + afterGroupMsgRead: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterGroupMsgRevoke: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + afterJoinGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + beforeInviteUserToGroup: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + joinGroupAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + setGroupInfoAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + setGroupInfoBefore: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + revokeMsgAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + addBlackBefore: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + addFriendAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + addFriendAgreeBefore: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + deleteFriendAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + importFriendsBefore: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + importFriendsAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} + removeBlackAfter: + enable: ${CALLBACK_ENABLE} + timeout: ${CALLBACK_TIMEOUT} + failedContinue: ${CALLBACK_FAILED_CONTINUE} ###################### Prometheus ###################### # Prometheus configuration for various services # The number of Prometheus ports per service needs to correspond to rpcPort diff --git a/docs/contrib/environment.md b/docs/contrib/environment.md index 6450549e7..0279c750e 100644 --- a/docs/contrib/environment.md +++ b/docs/contrib/environment.md @@ -501,7 +501,7 @@ This section involves setting up additional configuration variables for Websocke | TOKEN_EXPIRE | "90" | Token Expiry Time | | FRIEND_VERIFY | "false" | Friend Verification Enable | | IOS_PUSH_SOUND | "xxx" | iOS | -| CALLBACK_ENABLE | "true" | Enable callback | | | | +| CALLBACK_ENABLE | "false" | Enable callback | | CALLBACK_TIMEOUT | "5" | Maximum timeout for callback call | | CALLBACK_FAILED_CONTINUE| "true" | fails to continue to the next step | ### 2.20. Prometheus Configuration diff --git a/go.mod b/go.mod index fc7c615c6..8d767dbc1 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require github.com/google/uuid v1.3.1 require ( github.com/IBM/sarama v1.41.3 github.com/OpenIMSDK/protocol v0.0.31 - github.com/OpenIMSDK/tools v0.0.16 + github.com/OpenIMSDK/tools v0.0.17 github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible github.com/go-redis/redis v6.15.9+incompatible github.com/go-sql-driver/mysql v1.7.1 diff --git a/go.sum b/go.sum index 10cb9ee8c..640b11e89 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c= github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= github.com/OpenIMSDK/protocol v0.0.31 h1:ax43x9aqA6EKNXNukS5MT5BSTqkUmwO4uTvbJLtzCgE= github.com/OpenIMSDK/protocol v0.0.31/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.16 h1:te/GIq2imCMsrRPgU9OObYKbzZ3rT08Lih/o+3QFIz0= -github.com/OpenIMSDK/tools v0.0.16/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= +github.com/OpenIMSDK/tools v0.0.17 h1:1E1HUOL2W09YUHBb4wBwrXoTSZm5ONVwLxlEX1GhlKw= +github.com/OpenIMSDK/tools v0.0.17/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= diff --git a/internal/api/msg.go b/internal/api/msg.go index 38e207cfb..67b5f1eff 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -15,14 +15,6 @@ package api import ( - "github.com/OpenIMSDK/tools/mcontext" - "github.com/gin-gonic/gin" - "github.com/go-playground/validator/v10" - "github.com/mitchellh/mapstructure" - - "github.com/openimsdk/open-im-server/v3/pkg/authverify" - "github.com/openimsdk/open-im-server/v3/pkg/common/config" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/sdkws" @@ -30,7 +22,13 @@ import ( "github.com/OpenIMSDK/tools/apiresp" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" + "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "github.com/mitchellh/mapstructure" + "github.com/openimsdk/open-im-server/v3/pkg/authverify" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index 99a7a4805..5a061d7e1 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -121,6 +121,7 @@ func (ws *WsServer) UnRegister(c *Client) { } func (ws *WsServer) Validate(s interface{}) error { + //?question? return nil } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index b1a5ea6b5..fee2d5480 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -74,6 +74,9 @@ func (s *friendServer) RemoveBlack( return nil, err } s.notificationSender.BlackDeletedNotification(ctx, req) + if err := CallbackAfterRemoveBlack(ctx, req); err != nil { + return nil, err + } return &pbfriend.RemoveBlackResp{}, nil } @@ -85,6 +88,9 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) if err != nil { return nil, err } + if err := CallbackBeforeAddBlack(ctx, req); err != nil { + return nil, err + } black := relation.BlackModel{ OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID, diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go index d3b853ef9..d541071f5 100644 --- a/internal/rpc/friend/callback.go +++ b/internal/rpc/friend/callback.go @@ -16,9 +16,8 @@ package friend import ( "context" - "github.com/OpenIMSDK/tools/utils" - pbfriend "github.com/OpenIMSDK/protocol/friend" + "github.com/OpenIMSDK/tools/utils" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" @@ -33,6 +32,7 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend FromUserID: req.FromUserID, ToUserID: req.ToUserID, ReqMsg: req.ReqMsg, + Ex: req.Ex, } resp := &cbapi.CallbackBeforeAddFriendResp{} if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { @@ -75,3 +75,116 @@ func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRe } return nil } +func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) error { + if !config.Config.Callback.CallbackBeforeAddBlack.Enable { + return nil + } + cbReq := &cbapi.CallbackBeforeAddBlackReq{ + CallbackCommand: cbapi.CallbackBeforeAddBlackCommand, + OwnerUserID: req.OwnerUserID, + BlackUserID: req.BlackUserID, + } + resp := &cbapi.CallbackBeforeAddBlackResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddBlack); err != nil { + return err + } + return nil +} +func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { + if !config.Config.Callback.CallbackAfterAddFriend.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterAddFriendReq{ + CallbackCommand: cbapi.CallbackAfterAddFriendCommand, + FromUserID: req.FromUserID, + ToUserID: req.ToUserID, + ReqMsg: req.ReqMsg, + } + resp := &cbapi.CallbackAfterAddFriendResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterAddFriend); err != nil { + return err + } + + return nil +} +func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFriendApplyReq) error { + if !config.Config.Callback.CallbackBeforeAddFriendAgree.Enable { + return nil + } + cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ + CallbackCommand: cbapi.CallbackBeforeAddFriendAgreeCommand, + FromUserID: req.FromUserID, + ToUserID: req.ToUserID, + HandleMsg: req.HandleMsg, + HandleResult: req.HandleResult, + } + resp := &cbapi.CallbackBeforeAddFriendAgreeResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriendAgree); err != nil { + return err + } + return nil +} +func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) error { + if !config.Config.Callback.CallbackAfterDeleteFriend.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterDeleteFriendReq{ + CallbackCommand: cbapi.CallbackAfterDeleteFriendCommand, + OwnerUserID: req.OwnerUserID, + FriendUserID: req.FriendUserID, + } + resp := &cbapi.CallbackAfterDeleteFriendResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterDeleteFriend); err != nil { + return err + } + return nil +} +func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { + if !config.Config.Callback.CallbackBeforeImportFriends.Enable { + return nil + } + cbReq := &cbapi.CallbackBeforeImportFriendsReq{ + CallbackCommand: cbapi.CallbackBeforeImportFriendsCommand, + OwnerUserID: req.OwnerUserID, + FriendUserIDs: req.FriendUserIDs, + } + resp := &cbapi.CallbackBeforeImportFriendsResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeImportFriends); err != nil { + return err + } + if len(resp.FriendUserIDs) != 0 { + req.FriendUserIDs = resp.FriendUserIDs + } + return nil +} +func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { + if !config.Config.Callback.CallbackAfterImportFriends.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterImportFriendsReq{ + CallbackCommand: cbapi.CallbackAfterImportFriendsCommand, + OwnerUserID: req.OwnerUserID, + FriendUserIDs: req.FriendUserIDs, + } + resp := &cbapi.CallbackAfterImportFriendsResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterImportFriends); err != nil { + return err + } + return nil +} + +func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) error { + if !config.Config.Callback.CallbackAfterRemoveBlack.Enable { + return nil + } + cbReq := &cbapi.CallbackAfterRemoveBlackReq{ + CallbackCommand: cbapi.CallbackAfterRemoveBlackCommand, + OwnerUserID: req.OwnerUserID, + BlackUserID: req.BlackUserID, + } + resp := &cbapi.CallbackAfterRemoveBlackResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterRemoveBlack); err != nil { + return err + } + return nil +} diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 24014ace1..6e6b6d377 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -103,7 +103,7 @@ func (s *friendServer) ApplyToAddFriend( if req.ToUserID == req.FromUserID { return nil, errs.ErrCanNotAddYourself.Wrap() } - if err := CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { + if err = CallbackBeforeAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { return nil, err } if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { @@ -120,6 +120,9 @@ func (s *friendServer) ApplyToAddFriend( return nil, err } s.notificationSender.FriendApplicationAddNotification(ctx, req) + if err = CallbackAfterAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { + return nil, err + } return resp, nil } @@ -141,6 +144,10 @@ func (s *friendServer) ImportFriends( if utils.Duplicate(req.FriendUserIDs) { return nil, errs.ErrArgs.Wrap("friend userID repeated") } + if err := CallbackBeforeImportFriends(ctx, req); err != nil { + return nil, err + } + if err := s.friendDatabase.BecomeFriends(ctx, req.OwnerUserID, req.FriendUserIDs, constant.BecomeFriendByImport); err != nil { return nil, err } @@ -151,6 +158,9 @@ func (s *friendServer) ImportFriends( HandleResult: constant.FriendResponseAgree, }) } + if err := CallbackAfterImportFriends(ctx, req); err != nil { + return nil, err + } return &pbfriend.ImportFriendResp{}, nil } @@ -172,6 +182,9 @@ func (s *friendServer) RespondFriendApply( HandleResult: req.HandleResult, } if req.HandleResult == constant.FriendResponseAgree { + if err := CallbackBeforeAddFriendAgree(ctx, req); err != nil && err != errs.ErrCallbackContinue { + return nil, err + } err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) if err != nil { return nil, err @@ -208,6 +221,9 @@ func (s *friendServer) DeleteFriend( return nil, err } s.notificationSender.FriendDeletedNotification(ctx, req) + if err := CallbackAfterDeleteFriend(ctx, req); err != nil { + return nil, err + } return resp, nil } diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go index 13f9737b5..1599cc7b4 100644 --- a/internal/rpc/group/callback.go +++ b/internal/rpc/group/callback.go @@ -16,6 +16,7 @@ package group import ( "context" + "github.com/OpenIMSDK/tools/log" "time" "github.com/OpenIMSDK/protocol/constant" @@ -124,7 +125,14 @@ func CallbackBeforeMemberJoinGroup( GroupEx: groupEx, } resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeMemberJoinGroup); err != nil { + err = http.CallBackPostReturn( + ctx, + config.Config.Callback.CallbackUrl, + callbackReq, + resp, + config.Config.Callback.CallbackBeforeMemberJoinGroup, + ) + if err != nil { return err } if resp.MuteEndTime != nil { @@ -159,7 +167,14 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe callbackReq.Ex = &req.Ex.Value } resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupMemberInfo); err != nil { + err = http.CallBackPostReturn( + ctx, + config.Config.Callback.CallbackUrl, + callbackReq, + resp, + config.Config.Callback.CallbackBeforeSetGroupMemberInfo, + ) + if err != nil { return err } if resp.FaceURL != nil { @@ -176,13 +191,12 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe } return nil } - func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { return nil } callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ - CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand, + CallbackCommand: callbackstruct.CallbackAfterSetGroupMemberInfoCommand, GroupID: req.GroupID, UserID: req.UserID, } @@ -199,7 +213,7 @@ func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMem callbackReq.Ex = &req.Ex.Value } resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{} - if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupMemberInfo); err != nil { + if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupMemberInfo); err != nil { return err } return nil @@ -282,3 +296,135 @@ func CallbackTransferGroupOwnerAfter(ctx context.Context, req *pbgroup.TransferG } return nil } +func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserToGroupReq) (err error) { + if !config.Config.Callback.CallbackBeforeInviteUserToGroup.Enable { + return nil + } + + callbackReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{ + CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand, + OperationID: mcontext.GetOperationID(ctx), + GroupID: req.GroupID, + Reason: req.Reason, + InvitedUserIDs: req.InvitedUserIDs, + } + + resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{} + err = http.CallBackPostReturn( + ctx, + config.Config.Callback.CallbackUrl, + callbackReq, + resp, + config.Config.Callback.CallbackBeforeInviteUserToGroup, + ) + + if err != nil { + return err + } + + if len(resp.RefusedMembersAccount) > 0 { + // Handle the scenario where certain members are refused + // You might want to update the req.Members list or handle it as per your business logic + } + utils.StructFieldNotNilReplace(req, resp) + + return nil +} + +func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error { + if !config.Config.Callback.CallbackAfterJoinGroup.Enable { + return nil + } + callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{ + CallbackCommand: callbackstruct.CallbackAfterJoinGroupCommand, + OperationID: mcontext.GetOperationID(ctx), + GroupID: req.GroupID, + ReqMessage: req.ReqMessage, + JoinSource: req.JoinSource, + InviterUserID: req.InviterUserID, + } + resp := &callbackstruct.CallbackAfterJoinGroupResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterJoinGroup); err != nil { + return err + } + return nil +} + +func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { + if !config.Config.Callback.CallbackBeforeSetGroupInfo.Enable { + return nil + } + callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{ + CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand, + GroupID: req.GroupInfoForSet.GroupID, + Notification: req.GroupInfoForSet.Notification, + Introduction: req.GroupInfoForSet.Introduction, + FaceURL: req.GroupInfoForSet.FaceURL, + GroupName: req.GroupInfoForSet.GroupName, + } + + if req.GroupInfoForSet.Ex != nil { + callbackReq.Ex = req.GroupInfoForSet.Ex.Value + } + log.ZDebug(ctx, "debug CallbackBeforeSetGroupInfo", callbackReq.Ex) + if req.GroupInfoForSet.NeedVerification != nil { + callbackReq.NeedVerification = req.GroupInfoForSet.NeedVerification.Value + } + if req.GroupInfoForSet.LookMemberInfo != nil { + callbackReq.LookMemberInfo = req.GroupInfoForSet.LookMemberInfo.Value + } + if req.GroupInfoForSet.ApplyMemberFriend != nil { + callbackReq.ApplyMemberFriend = req.GroupInfoForSet.ApplyMemberFriend.Value + } + resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{} + + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupInfo); err != nil { + return err + } + + if resp.Ex != nil { + req.GroupInfoForSet.Ex = wrapperspb.String(*resp.Ex) + } + if resp.NeedVerification != nil { + req.GroupInfoForSet.NeedVerification = wrapperspb.Int32(*resp.NeedVerification) + } + if resp.LookMemberInfo != nil { + req.GroupInfoForSet.LookMemberInfo = wrapperspb.Int32(*resp.LookMemberInfo) + } + if resp.ApplyMemberFriend != nil { + req.GroupInfoForSet.ApplyMemberFriend = wrapperspb.Int32(*resp.ApplyMemberFriend) + } + utils.StructFieldNotNilReplace(req, resp) + return nil +} +func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { + if !config.Config.Callback.CallbackAfterSetGroupInfo.Enable { + return nil + } + callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{ + CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoCommand, + GroupID: req.GroupInfoForSet.GroupID, + Notification: req.GroupInfoForSet.Notification, + Introduction: req.GroupInfoForSet.Introduction, + FaceURL: req.GroupInfoForSet.FaceURL, + GroupName: req.GroupInfoForSet.GroupName, + } + if req.GroupInfoForSet.Ex != nil { + callbackReq.Ex = &req.GroupInfoForSet.Ex.Value + } + if req.GroupInfoForSet.NeedVerification != nil { + callbackReq.NeedVerification = &req.GroupInfoForSet.NeedVerification.Value + } + if req.GroupInfoForSet.LookMemberInfo != nil { + callbackReq.LookMemberInfo = &req.GroupInfoForSet.LookMemberInfo.Value + } + if req.GroupInfoForSet.ApplyMemberFriend != nil { + callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value + } + resp := &callbackstruct.CallbackAfterSetGroupInfoResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterSetGroupInfo); err != nil { + return err + } + utils.StructFieldNotNilReplace(req, resp) + return nil +} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 227b7959d..67cd70817 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -366,6 +366,7 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.InviteUserToGroupReq) (*pbgroup.InviteUserToGroupResp, error) { resp := &pbgroup.InviteUserToGroupResp{} + if len(req.InvitedUserIDs) == 0 { return nil, errs.ErrArgs.Wrap("user empty") } @@ -376,6 +377,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite if err != nil { return nil, err } + if group.Status == constant.GroupStatusDismissed { return nil, errs.ErrDismissedAlready.Wrap() } @@ -399,6 +401,10 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } groupMember = groupMembers[0] } + + if err := CallbackBeforeInviteUserToGroup(ctx, req); err != nil { + return nil, err + } if group.NeedVerification == constant.AllNeedVerification { if !authverify.IsAppManagerUid(ctx) { if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { @@ -413,6 +419,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite HandledTime: time.Unix(0, 0), }) } + if err := s.GroupDatabase.CreateGroupRequest(ctx, requests); err != nil { return nil, err } @@ -818,6 +825,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup case constant.GroupResponseRefuse: s.Notification.GroupApplicationRejectedNotification(ctx, req) } + return &pbgroup.GroupApplicationResponseResp{}, nil } @@ -872,10 +880,14 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err := s.GroupDatabase.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { return nil, err } + if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil { return nil, err } s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) + if err = CallbackAfterJoinGroup(ctx, req); err != nil { + return nil, err + } return resp, nil } groupRequest := relationtb.GroupRequestModel{ @@ -957,6 +969,9 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf return nil, errs.ErrNoPermission.Wrap("no group owner or admin") } } + if err := CallbackBeforeSetGroupInfo(ctx, req); err != nil { + return nil, err + } group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupInfoForSet.GroupID) if err != nil { return nil, err @@ -1025,6 +1040,9 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf default: s.Notification.GroupInfoSetNotification(ctx, tips) } + if err := CallbackAfterSetGroupInfo(ctx, req); err != nil { + return nil, err + } return resp, nil } diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go index 85c002bf3..4ce5a5443 100644 --- a/internal/rpc/msg/callback.go +++ b/internal/rpc/msg/callback.go @@ -24,8 +24,8 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" - cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/http" ) @@ -98,10 +98,10 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err } func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { - if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable { + if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable { return nil } - req := &cbapi.CallbackAfterSendGroupMsgReq{ + req := &cbapi.CallbackBeforeSendGroupMsgReq{ CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackBeforeSendGroupMsgCommand), GroupID: msg.MsgData.GroupID, } @@ -160,7 +160,6 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) return nil } - func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error { if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { return nil @@ -180,10 +179,27 @@ func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgRead } req.CallbackCommand = cbapi.CallbackSingleMsgRead - resp := &cbapi.CallbackGroupMsgReadResp{} + resp := &cbapi.CallbackSingleMsgReadResp{} if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { return err } return nil } +func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error { + if !config.Config.Callback.CallbackAfterRevokeMsg.Enable { + return nil + } + callbackReq := &cbapi.CallbackAfterRevokeMsgReq{ + CallbackCommand: cbapi.CallbackAfterRevokeMsgCommand, + ConversationID: req.ConversationID, + Seq: req.Seq, + UserID: req.UserID, + } + resp := &cbapi.CallbackAfterRevokeMsgResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, callbackReq, resp, config.Config.Callback.CallbackAfterRevokeMsg); err != nil { + return err + } + utils.StructFieldNotNilReplace(req, resp) + return nil +} diff --git a/internal/rpc/msg/revoke.go b/internal/rpc/msg/revoke.go index 151d29fc1..d7362d339 100644 --- a/internal/rpc/msg/revoke.go +++ b/internal/rpc/msg/revoke.go @@ -61,6 +61,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if msgs[0].ContentType == constant.MsgRevokeNotification { return nil, errs.ErrMsgAlreadyRevoke.Wrap("msg already revoke") } + data, _ := json.Marshal(msgs[0]) log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) var role int32 @@ -128,5 +129,8 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg. if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil { return nil, err } + if err = CallbackAfterRevokeMsg(ctx, req); err != nil { + return nil, err + } return &msg.RevokeMsgResp{}, nil } diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go index 01de2734d..e87b4674e 100644 --- a/internal/rpc/user/callback.go +++ b/internal/rpc/user/callback.go @@ -91,8 +91,8 @@ func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) Users: req.Users, } - resp := &cbapi.CallbackBeforeUserRegisterResp{} - if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { + resp := &cbapi.CallbackAfterUserRegisterResp{} + if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackAfterUpdateUserInfo); err != nil { return err } return nil diff --git a/pkg/apistruct/msg.go b/pkg/apistruct/msg.go index 12cf253a0..61b4d832b 100644 --- a/pkg/apistruct/msg.go +++ b/pkg/apistruct/msg.go @@ -16,56 +16,56 @@ package apistruct type PictureBaseInfo struct { UUID string `mapstructure:"uuid"` - Type string `mapstructure:"type"` + Type string `mapstructure:"type" validate:"required"` Size int64 `mapstructure:"size"` - Width int32 `mapstructure:"width"` - Height int32 `mapstructure:"height"` - Url string `mapstructure:"url"` + Width int32 `mapstructure:"width" validate:"required"` + Height int32 `mapstructure:"height" validate:"required"` + Url string `mapstructure:"url" validate:"required"` } type PictureElem struct { SourcePath string `mapstructure:"sourcePath"` - SourcePicture PictureBaseInfo `mapstructure:"sourcePicture"` - BigPicture PictureBaseInfo `mapstructure:"bigPicture"` - SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture"` + SourcePicture PictureBaseInfo `mapstructure:"sourcePicture" validate:"required"` + BigPicture PictureBaseInfo `mapstructure:"bigPicture" validate:"required"` + SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture" validate:"required"` } type SoundElem struct { UUID string `mapstructure:"uuid"` SoundPath string `mapstructure:"soundPath"` - SourceURL string `mapstructure:"sourceUrl"` + SourceURL string `mapstructure:"sourceUrl" validate:"required"` DataSize int64 `mapstructure:"dataSize"` - Duration int64 `mapstructure:"duration"` + Duration int64 `mapstructure:"duration" validate:"required,min=1"` } type VideoElem struct { - VideoPath string `mapstructure:"videoPath"` + VideoPath string `mapstructure:"videoPath" ` VideoUUID string `mapstructure:"videoUUID"` - VideoURL string `mapstructure:"videoUrl"` - VideoType string `mapstructure:"videoType"` - VideoSize int64 `mapstructure:"videoSize"` - Duration int64 `mapstructure:"duration"` + VideoURL string `mapstructure:"videoUrl" validate:"required"` + VideoType string `mapstructure:"videoType" validate:"required"` + VideoSize int64 `mapstructure:"videoSize" validate:"required"` + Duration int64 `mapstructure:"duration" validate:"required"` SnapshotPath string `mapstructure:"snapshotPath"` SnapshotUUID string `mapstructure:"snapshotUUID"` SnapshotSize int64 `mapstructure:"snapshotSize"` - SnapshotURL string `mapstructure:"snapshotUrl"` - SnapshotWidth int32 `mapstructure:"snapshotWidth"` - SnapshotHeight int32 `mapstructure:"snapshotHeight"` + SnapshotURL string `mapstructure:"snapshotUrl" validate:"required"` + SnapshotWidth int32 `mapstructure:"snapshotWidth" validate:"required"` + SnapshotHeight int32 `mapstructure:"snapshotHeight" validate:"required"` } type FileElem struct { - FilePath string `mapstructure:"filePath"` + FilePath string `mapstructure:"filePath" ` UUID string `mapstructure:"uuid"` - SourceURL string `mapstructure:"sourceUrl"` - FileName string `mapstructure:"fileName"` - FileSize int64 `mapstructure:"fileSize"` + SourceURL string `mapstructure:"sourceUrl" validate:"required"` + FileName string `mapstructure:"fileName" validate:"required"` + FileSize int64 `mapstructure:"fileSize" validate:"required"` } type AtElem struct { Text string `mapstructure:"text"` - AtUserList []string `mapstructure:"atUserList"` + AtUserList []string `mapstructure:"atUserList" validate:"required,max=1000"` IsAtSelf bool `mapstructure:"isAtSelf"` } type LocationElem struct { - Description string `mapstructure:"description"` - Longitude float64 `mapstructure:"longitude"` - Latitude float64 `mapstructure:"latitude"` + Description string `mapstructure:"description" ` + Longitude float64 `mapstructure:"longitude" validate:"required"` + Latitude float64 `mapstructure:"latitude" validate:"required"` } type CustomElem struct { Data string `mapstructure:"data" validate:"required"` @@ -80,18 +80,19 @@ type TextElem struct { type RevokeElem struct { RevokeMsgClientID string `mapstructure:"revokeMsgClientID" validate:"required"` } + type OANotificationElem struct { - NotificationName string `mapstructure:"notificationName" json:"notificationName" validate:"required"` - NotificationFaceURL string `mapstructure:"notificationFaceURL" json:"notificationFaceURL"` - NotificationType int32 `mapstructure:"notificationType" json:"notificationType" validate:"required"` - Text string `mapstructure:"text" json:"text" validate:"required"` - Url string `mapstructure:"url" json:"url"` - MixType int32 `mapstructure:"mixType" json:"mixType"` - PictureElem PictureElem `mapstructure:"pictureElem" json:"pictureElem"` - SoundElem SoundElem `mapstructure:"soundElem" json:"soundElem"` - VideoElem VideoElem `mapstructure:"videoElem" json:"videoElem"` - FileElem FileElem `mapstructure:"fileElem" json:"fileElem"` - Ex string `mapstructure:"ex" json:"ex"` + NotificationName string `mapstructure:"notificationName" json:"notificationName" validate:"required"` + NotificationFaceURL string `mapstructure:"notificationFaceURL" json:"notificationFaceURL"` + NotificationType int32 `mapstructure:"notificationType" json:"notificationType" validate:"required"` + Text string `mapstructure:"text" json:"text" validate:"required"` + Url string `mapstructure:"url" json:"url"` + MixType int32 `mapstructure:"mixType" json:"mixType" validate:"required"` + PictureElem *PictureElem `mapstructure:"pictureElem" json:"pictureElem"` + SoundElem *SoundElem `mapstructure:"soundElem" json:"soundElem"` + VideoElem *VideoElem `mapstructure:"videoElem" json:"videoElem"` + FileElem *FileElem `mapstructure:"fileElem" json:"fileElem"` + Ex string `mapstructure:"ex" json:"ex"` } type MessageRevoked struct { RevokerID string `mapstructure:"revokerID" json:"revokerID" validate:"required"` diff --git a/pkg/callbackstruct/constant.go b/pkg/callbackstruct/constant.go index f029e3713..2af337ac6 100644 --- a/pkg/callbackstruct/constant.go +++ b/pkg/callbackstruct/constant.go @@ -1,5 +1,20 @@ package callbackstruct +const CallbackBeforeInviteJoinGroupCommand = "callbackBeforeInviteJoinGroupCommand" +const CallbackAfterJoinGroupCommand = "callbackAfterJoinGroupCommand" +const CallbackAfterSetGroupInfoCommand = "callbackAfterSetGroupInfoCommand" +const CallbackBeforeSetGroupInfoCommand = "callbackBeforeSetGroupInfoCommand" + +const CallbackAfterRevokeMsgCommand = "callbackBeforeAfterMsgCommand" +const CallbackBeforeAddBlackCommand = "callbackBeforeAddBlackCommand" +const CallbackAfterAddFriendCommand = "callbackAfterAddFriendCommand" +const CallbackBeforeAddFriendAgreeCommand = "callbackBeforeAddFriendAgreeCommand" + +const CallbackAfterDeleteFriendCommand = "callbackAfterDeleteFriendCommand" +const CallbackBeforeImportFriendsCommand = "callbackBeforeImportFriendsCommand" +const CallbackAfterImportFriendsCommand = "callbackAfterImportFriendsCommand" +const CallbackAfterRemoveBlackCommand = "callbackAfterRemoveBlackCommand" + const ( CallbackQuitGroupCommand = "callbackQuitGroupCommand" CallbackKillGroupCommand = "callbackKillGroupCommand" @@ -29,5 +44,6 @@ const ( CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand" CallbackAfterCreateGroupCommand = "callbackAfterCreateGroupCommand" CallbackBeforeMemberJoinGroupCommand = "callbackBeforeMemberJoinGroupCommand" - CallbackBeforeSetGroupMemberInfoCommand = "CallbackBeforeSetGroupMemberInfoCommand" + CallbackBeforeSetGroupMemberInfoCommand = "callbackBeforeSetGroupMemberInfoCommand" + CallbackAfterSetGroupMemberInfoCommand = "callbackAfterSetGroupMemberInfoCommand" ) diff --git a/pkg/callbackstruct/friend.go b/pkg/callbackstruct/friend.go index ebbd08b19..3674a34da 100644 --- a/pkg/callbackstruct/friend.go +++ b/pkg/callbackstruct/friend.go @@ -19,6 +19,7 @@ type CallbackBeforeAddFriendReq struct { FromUserID string `json:"fromUserID" ` ToUserID string `json:"toUserID"` ReqMsg string `json:"reqMsg"` + Ex string `json:"ex"` } type CallbackBeforeAddFriendResp struct { @@ -35,6 +36,28 @@ type CallBackAddFriendReplyBeforeResp struct { CommonCallbackResp } +type CallbackBeforeSetFriendRemarkReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID"` + FriendUserID string `json:"friendUserID"` + Remark string `json:"remark"` +} + +type CallbackBeforeSetFriendRemarkResp struct { + CommonCallbackResp + Remark string `json:"remark"` +} + +type CallbackAfterSetFriendRemarkReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID"` + FriendUserID string `json:"friendUserID"` + Remark string `json:"remark"` +} + +type CallbackAfterSetFriendRemarkResp struct { + CommonCallbackResp +} type CallbackAfterAddFriendReq struct { CallbackCommand `json:"callbackCommand"` FromUserID string `json:"fromUserID" ` @@ -45,26 +68,60 @@ type CallbackAfterAddFriendReq struct { type CallbackAfterAddFriendResp struct { CommonCallbackResp } +type CallbackBeforeAddBlackReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID" ` + BlackUserID string `json:"blackUserID"` +} -type CallbackBeforeSetFriendRemarkReq struct { +type CallbackBeforeAddBlackResp struct { + CommonCallbackResp +} + +type CallbackBeforeAddFriendAgreeReq struct { CallbackCommand `json:"callbackCommand"` - OwnerUserID string `json:"ownerUserID"` - FriendUserID string `json:"friendUserID"` - Remark string `json:"remark"` + FromUserID string `json:"fromUserID" ` + ToUserID string `json:"blackUserID"` + HandleResult int32 `json:"HandleResult"` + HandleMsg string `json:"HandleMsg"` } -type CallbackBeforeSetFriendRemarkResp struct { +type CallbackBeforeAddFriendAgreeResp struct { CommonCallbackResp - Remark string `json:"remark"` } -type CallbackAfterSetFriendRemarkReq struct { +type CallbackAfterDeleteFriendReq struct { CallbackCommand `json:"callbackCommand"` - OwnerUserID string `json:"ownerUserID"` + OwnerUserID string `json:"ownerUserID" ` FriendUserID string `json:"friendUserID"` - Remark string `json:"remark"` +} +type CallbackAfterDeleteFriendResp struct { + CommonCallbackResp } -type CallbackAfterSetFriendRemarkResp struct { +type CallbackBeforeImportFriendsReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID" ` + FriendUserIDs []string `json:"friendUserIDs"` +} +type CallbackBeforeImportFriendsResp struct { + CommonCallbackResp + FriendUserIDs []string `json:"friendUserIDs"` +} +type CallbackAfterImportFriendsReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID" ` + FriendUserIDs []string `json:"friendUserIDs"` +} +type CallbackAfterImportFriendsResp struct { + CommonCallbackResp +} + +type CallbackAfterRemoveBlackReq struct { + CallbackCommand `json:"callbackCommand"` + OwnerUserID string `json:"ownerUserID"` + BlackUserID string `json:"blackUserID"` +} +type CallbackAfterRemoveBlackResp struct { CommonCallbackResp } diff --git a/pkg/callbackstruct/group.go b/pkg/callbackstruct/group.go index 79e02ba0f..899b4312f 100644 --- a/pkg/callbackstruct/group.go +++ b/pkg/callbackstruct/group.go @@ -109,108 +109,127 @@ type CallbackAfterSetGroupMemberInfoResp struct { CommonCallbackResp } -type CallbackAfterGroupMemberExitReq struct { +type CallbackQuitGroupReq struct { CallbackCommand `json:"callbackCommand"` GroupID string `json:"groupID"` UserID string `json:"userID"` - GroupType *int32 `json:"groupType"` - ExitType string `json:"exitType"` } -type CallbackAfterGroupMemberExitResp struct { +type CallbackQuitGroupResp struct { CommonCallbackResp } -type CallbackAfterUngroupReq struct { +type CallbackKillGroupMemberReq struct { CallbackCommand `json:"callbackCommand"` GroupID string `json:"groupID"` - GroupType *int32 `json:"groupType"` - OwnerID string `json:"ownerID"` - MemberList []string `json:"memberList"` + KickedUserIDs []string `json:"kickedUserIDs"` + Reason string `json:"reason"` } -type CallbackAfterUngroupResp struct { +type CallbackKillGroupMemberResp struct { CommonCallbackResp } -type CallbackAfterSetGroupInfoReq struct { +type CallbackDisMissGroupReq struct { CallbackCommand `json:"callbackCommand"` - GroupID string `json:"groupID"` - GroupType *int32 `json:"groupType"` - UserID string `json:"userID"` - Name string `json:"name"` - Notification string `json:"notification"` - GroupUrl string `json:"groupUrl"` + GroupID string `json:"groupID"` + OwnerID string `json:"ownerID"` + GroupType string `json:"groupType"` + MembersID []string `json:"membersID"` } -type CallbackAfterSetGroupInfoResp struct { +type CallbackDisMissGroupResp struct { CommonCallbackResp } -type CallbackAfterRevokeMsgReq struct { +type CallbackJoinGroupReq struct { CallbackCommand `json:"callbackCommand"` GroupID string `json:"groupID"` - GroupType *int32 `json:"groupType"` - UserID string `json:"userID"` - Content string `json:"content"` + GroupType string `json:"groupType"` + ApplyID string `json:"applyID"` + ReqMessage string `json:"reqMessage"` } -type CallbackAfterRevokeMsgResp struct { +type CallbackJoinGroupResp struct { CommonCallbackResp } -type CallbackQuitGroupReq struct { +type CallbackTransferGroupOwnerReq struct { CallbackCommand `json:"callbackCommand"` GroupID string `json:"groupID"` - UserID string `json:"userID"` + OldOwnerUserID string `json:"oldOwnerUserID"` + NewOwnerUserID string `json:"newOwnerUserID"` } -type CallbackQuitGroupResp struct { +type CallbackTransferGroupOwnerResp struct { CommonCallbackResp } -type CallbackKillGroupMemberReq struct { +type CallbackBeforeInviteUserToGroupReq struct { CallbackCommand `json:"callbackCommand"` + OperationID string `json:"operationID"` GroupID string `json:"groupID"` - KickedUserIDs []string `json:"kickedUserIDs"` Reason string `json:"reason"` + InvitedUserIDs []string `json:"invitedUserIDs"` } - -type CallbackKillGroupMemberResp struct { +type CallbackBeforeInviteUserToGroupResp struct { CommonCallbackResp + RefusedMembersAccount []string `json:"refusedMembersAccount,omitempty"` // Optional field to list members whose invitation is refused. } -type CallbackDisMissGroupReq struct { +type CallbackAfterJoinGroupReq struct { CallbackCommand `json:"callbackCommand"` - GroupID string `json:"groupID"` - OwnerID string `json:"ownerID"` - GroupType string `json:"groupType"` - MembersID []string `json:"membersID"` + OperationID string `json:"operationID"` + GroupID string `json:"groupID"` + ReqMessage string `json:"reqMessage"` + JoinSource int32 `json:"joinSource"` + InviterUserID string `json:"inviterUserID"` } - -type CallbackDisMissGroupResp struct { +type CallbackAfterJoinGroupResp struct { CommonCallbackResp } -type CallbackJoinGroupReq struct { - CallbackCommand `json:"callbackCommand"` - GroupID string `json:"groupID"` - GroupType string `json:"groupType"` - ApplyID string `json:"applyID"` - ReqMessage string `json:"reqMessage"` +type CallbackBeforeSetGroupInfoReq struct { + CallbackCommand `json:"callbackCommand"` + OperationID string `json:"operationID"` + GroupID string `json:"groupID"` + GroupName string `json:"groupName"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + FaceURL string `json:"faceURL"` + Ex string `json:"ex"` + NeedVerification int32 `json:"needVerification"` + LookMemberInfo int32 `json:"lookMemberInfo"` + ApplyMemberFriend int32 `json:"applyMemberFriend"` } -type CallbackJoinGroupResp struct { +type CallbackBeforeSetGroupInfoResp struct { CommonCallbackResp + GroupID string ` json:"groupID"` + GroupName string `json:"groupName"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + FaceURL string `json:"faceURL"` + Ex *string `json:"ex"` + NeedVerification *int32 `json:"needVerification"` + LookMemberInfo *int32 `json:"lookMemberInfo"` + ApplyMemberFriend *int32 `json:"applyMemberFriend"` } -type CallbackTransferGroupOwnerReq struct { - CallbackCommand `json:"callbackCommand"` - GroupID string `json:"groupID"` - OldOwnerUserID string `json:"oldOwnerUserID"` - NewOwnerUserID string `json:"newOwnerUserID"` +type CallbackAfterSetGroupInfoReq struct { + CallbackCommand `json:"callbackCommand"` + OperationID string `json:"operationID"` + GroupID string `json:"groupID"` + GroupName string `json:"groupName"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + FaceURL string `json:"faceURL"` + Ex *string `json:"ex"` + NeedVerification *int32 `json:"needVerification"` + LookMemberInfo *int32 `json:"lookMemberInfo"` + ApplyMemberFriend *int32 `json:"applyMemberFriend"` } -type CallbackTransferGroupOwnerResp struct { +type CallbackAfterSetGroupInfoResp struct { CommonCallbackResp } diff --git a/pkg/callbackstruct/message.go b/pkg/callbackstruct/message.go index 3adee618b..ae36d7139 100644 --- a/pkg/callbackstruct/message.go +++ b/pkg/callbackstruct/message.go @@ -80,26 +80,6 @@ type CallbackMsgModifyCommandResp struct { Ex *string `json:"ex"` } -type CallbackSendGroupMsgErrorReq struct { - CommonCallbackReq - GroupID string `json:"groupID"` -} - -type CallbackSendGroupMsgErrorResp struct { - CommonCallbackResp -} - -type CallbackSingleMsgRevokeReq struct { - CallbackCommand `json:"callbackCommand"` - SendID string `json:"sendID"` - ReceiveID string `json:"receiveID"` - Content string `json:"content"` -} - -type CallbackSingleMsgRevokeResp struct { - CommonCallbackResp -} - type CallbackGroupMsgReadReq struct { CallbackCommand `json:"callbackCommand"` SendID string `json:"sendID"` diff --git a/pkg/callbackstruct/revoke.go b/pkg/callbackstruct/revoke.go new file mode 100644 index 000000000..364c0162b --- /dev/null +++ b/pkg/callbackstruct/revoke.go @@ -0,0 +1,11 @@ +package callbackstruct + +type CallbackAfterRevokeMsgReq struct { + CallbackCommand `json:"callbackCommand"` + ConversationID string `json:"conversationID"` + Seq int64 `json:"seq"` + UserID string `json:"userID"` +} +type CallbackAfterRevokeMsgResp struct { + CommonCallbackResp +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index d8bee6af8..3c819ea2c 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -16,7 +16,6 @@ package config import ( "bytes" - "github.com/OpenIMSDK/tools/discoveryregistry" "gopkg.in/yaml.v3" ) @@ -282,11 +281,25 @@ type configStruct struct { CallbackAfterCreateGroup CallBackConfig `yaml:"afterCreateGroup"` CallbackBeforeMemberJoinGroup CallBackConfig `yaml:"beforeMemberJoinGroup"` CallbackBeforeSetGroupMemberInfo CallBackConfig `yaml:"beforeSetGroupMemberInfo"` + CallbackAfterSetGroupMemberInfo CallBackConfig `yaml:"afterSetGroupMemberInfo"` CallbackQuitGroup CallBackConfig `yaml:"quitGroup"` CallbackKillGroupMember CallBackConfig `yaml:"killGroupMember"` CallbackDismissGroup CallBackConfig `yaml:"dismissGroup"` CallbackBeforeJoinGroup CallBackConfig `yaml:"joinGroup"` CallbackTransferGroupOwnerAfter CallBackConfig `yaml:"transferGroupOwner"` + CallbackBeforeInviteUserToGroup CallBackConfig `yaml:"beforeInviteUserToGroup"` + CallbackAfterJoinGroup CallBackConfig `yaml:"joinGroupAfter"` + CallbackAfterSetGroupInfo CallBackConfig `yaml:"setGroupInfoAfter"` + CallbackBeforeSetGroupInfo CallBackConfig `yaml:"setGroupInfoBefore"` + CallbackAfterRevokeMsg CallBackConfig `yaml:"revokeMsgAfter"` + CallbackBeforeAddBlack CallBackConfig `yaml:"addBlackBefore"` + CallbackAfterAddFriend CallBackConfig `yaml:"addFriendAfter"` + CallbackBeforeAddFriendAgree CallBackConfig `yaml:"addFriendAgreeBefore"` + + CallbackAfterDeleteFriend CallBackConfig `yaml:"deleteFriendAfter"` + CallbackBeforeImportFriends CallBackConfig `yaml:"importFriendsBefore"` + CallbackAfterImportFriends CallBackConfig `yaml:"importFriendsAfter"` + CallbackAfterRemoveBlack CallBackConfig `yaml:"removeBlackAfter"` } `yaml:"callback"` Prometheus struct { diff --git a/scripts/install/environment.sh b/scripts/install/environment.sh index 98636bbde..b7c8a5dcb 100755 --- a/scripts/install/environment.sh +++ b/scripts/install/environment.sh @@ -386,10 +386,9 @@ def "IOS_PUSH_SOUND" "xxx" # IOS推送声音 def "IOS_BADGE_COUNT" "true" # IOS徽章计数 def "IOS_PRODUCTION" "false" # IOS生产 # callback 配置 -def "CALLBACK_ENABLE" "true" # 是否开启 Callback +def "CALLBACK_ENABLE" "false" # 是否开启 Callback def "CALLBACK_TIMEOUT" "5" # 最长超时时间 def "CALLBACK_FAILED_CONTINUE" "true" # 失败后是否继续 - ###################### Prometheus 配置信息 ###################### # 是否启用 Prometheus readonly PROMETHEUS_ENABLE=${PROMETHEUS_ENABLE:-'false'} From 5b697d5e95f54aaca7c199f283d19bf19745848a Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Thu, 30 Nov 2023 16:57:06 +0800 Subject: [PATCH 14/18] feat: update openim pull message by seq (#1498) --- scripts/install/test.sh | 52 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/scripts/install/test.sh b/scripts/install/test.sh index eb3f6a200..049dc19c8 100755 --- a/scripts/install/test.sh +++ b/scripts/install/test.sh @@ -1202,6 +1202,40 @@ EOF openim::test::check_error "$response" } +# Pulls messages by sequence. +openim::test::pull_msg_by_seq() { + local userID="${1}" + local conversationID="${2}" + local beginSeq="${3}" + local endSeq="${4}" + local num="${5}" + local order="${6}" # Assuming 0 for ascending, 1 for descending + + # Construct the request body + local request_body=$(cat < Date: Thu, 30 Nov 2023 16:58:53 +0800 Subject: [PATCH 15/18] docs: add rfyiamcool to code_owners (#1491) * docs: add rfyiamcool to code_owners Signed-off-by: rfyiamcool * Update CODEOWNERS --------- Signed-off-by: rfyiamcool Co-authored-by: Xinwei Xiong <3293172751@qq.com> --- docs/CODEOWNERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 95babf0d1..d1119eb61 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -2,28 +2,28 @@ # Each line is a file pattern followed by one or more owners. # README files -README.md @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +README.md @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # Contributing guidelines -CONTRIBUTING.md @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +CONTRIBUTING.md @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # License files -LICENSE @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +LICENSE @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # Makefile -Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, # @cubxxw and @openimsdk/bot will be requested for # review when someone opens a pull request. -* @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +* @openimsdk/openim @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # Order is important; the last matching pattern takes the most # precedence. When someone opens a pull request that only # modifies JS files, only @js-owner and not the global # owner(s) will be requested for a review. -*.js @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +*.js @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # You can also use email addresses if you prefer. They'll be # used to look up users just like we do for commit author @@ -35,7 +35,7 @@ Makefile @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangch # be identified in the format @org/team-name. Teams must have # explicit write access to the repository. In this example, # the OpenIMSDK team in the github organization owns all .txt files. -*.txt @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @wangchuxiao-dev @withchao +*.txt @cubxxw @openimsdk/bot @Bloomingg @FGadvancer @skiffer-git @rfyiamcool @withchao # The `docs/*` pattern will match files like # `docs/getting-started.md` but not further nested files like From 4b192027aadebeb16a0190feb4ef5a4e726a463d Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Thu, 30 Nov 2023 18:25:38 +0800 Subject: [PATCH 16/18] =?UTF-8?q?=E2=93=82=EF=B8=8Ffeat:=20openim=20docker?= =?UTF-8?q?=20fix=20=20(#1502)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: fix auto gen config Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * feat: add openim openim compatibility Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix ai fix git commit continue-on-error: true Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix ai fix git commit continue-on-error: true Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix ai fix git commit continue-on-error: true Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix ai fix git commit continue-on-error: true Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix ai fix git commit continue-on-error: true Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> --------- Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> --- .dockerignore | 1 - .env | 315 ------------------ .github/workflows/e2e-test.yml | 7 +- .github/workflows/opencommit.yml | 3 +- .github/workflows/openimci.yml | 6 +- .gitignore | 1 + Dockerfile | 5 +- config/alertmanager.yml | 32 -- config/config.yaml | 409 ------------------------ deployments/templates/env_template.yaml | 44 +-- install.sh | 14 +- install_guide.sh | 6 +- scripts/init-pwd.sh | 70 ---- 13 files changed, 28 insertions(+), 885 deletions(-) delete mode 100644 .env delete mode 100644 config/alertmanager.yml delete mode 100644 config/config.yaml delete mode 100755 scripts/init-pwd.sh diff --git a/.dockerignore b/.dockerignore index 705512401..263798e07 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,7 +20,6 @@ CHANGELOG/ # Ignore deployment-related files docker-compose.yaml -deployments/ # Ignore assets assets/ diff --git a/.env b/.env deleted file mode 100644 index 8213b9e3c..000000000 --- a/.env +++ /dev/null @@ -1,315 +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. - -# ====================================== -# ========= Basic Configuration ======== -# ====================================== - -# The user for authentication or system operations. -# Default: USER=root -USER=root - -# Password associated with the specified user for authentication. -# Default: PASSWORD=openIM123 -PASSWORD=openIM123 - -# Endpoint for the MinIO object storage service. -# Default: MINIO_ENDPOINT=http://172.28.0.1:10005 -MINIO_ENDPOINT=http://172.28.0.1:10005 - -# Base URL for the application programming interface (API). -# Default: API_URL=http://172.28.0.1:10002 -API_URL=http://172.28.0.1:10002 - -# Directory path for storing data files or related information. -# Default: DATA_DIR=./ -DATA_DIR=./ - -# Choose the appropriate image address, the default is GITHUB image, -# you can choose docker hub, for Chinese users can choose Ali Cloud -# export IMAGE_REGISTRY="ghcr.io/openimsdk" -# export IMAGE_REGISTRY="openim" -# export IMAGE_REGISTRY="registry.cn-hangzhou.aliyuncs.com/openimsdk" -IMAGE_REGISTRY=ghcr.io/openimsdk - -# ====================================== -# ========= Network Configuration ====== -# ====================================== - -# Subnet for the Docker network. -# Default: DOCKER_BRIDGE_SUBNET=172.28.0.0/16 -DOCKER_BRIDGE_SUBNET=172.28.0.0/16 - -# Gateway for the Docker network. -# Default: DOCKER_BRIDGE_GATEWAY=172.28.0.1 -DOCKER_BRIDGE_GATEWAY=172.28.0.1 - -# Address or hostname for the MySQL network. -# Default: MYSQL_NETWORK_ADDRESS=172.28.0.2 -MYSQL_NETWORK_ADDRESS=172.28.0.2 - -# Address or hostname for the MongoDB network. -# Default: MONGO_NETWORK_ADDRESS=172.28.0.3 -MONGO_NETWORK_ADDRESS=172.28.0.3 - -# Address or hostname for the Redis network. -# Default: REDIS_NETWORK_ADDRESS=172.28.0.4 -REDIS_NETWORK_ADDRESS=172.28.0.4 - -# Address or hostname for the Kafka network. -# Default: KAFKA_NETWORK_ADDRESS=172.28.0.5 -KAFKA_NETWORK_ADDRESS=172.28.0.5 - -# Address or hostname for the ZooKeeper network. -# Default: ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6 -ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6 - -# Address or hostname for the MinIO network. -# Default: MINIO_NETWORK_ADDRESS=172.28.0.7 -MINIO_NETWORK_ADDRESS=172.28.0.7 - -# Address or hostname for the OpenIM web network. -# Default: OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8 -OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8 - -# Address or hostname for the OpenIM server network. -# Default: OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9 -OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9 - -# Address or hostname for the OpenIM chat network. -# Default: OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10 -OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10 - -# Address or hostname for the Prometheus network. -# Default: PROMETHEUS_NETWORK_ADDRESS=172.28.0.11 -PROMETHEUS_NETWORK_ADDRESS=172.28.0.11 - -# Address or hostname for the Grafana network. -# Default: GRAFANA_NETWORK_ADDRESS=172.28.0.12 -GRAFANA_NETWORK_ADDRESS=172.28.0.12 - -# Address or hostname for the node_exporter network. -# Default: NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.13 -NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.13 - -# Address or hostname for the OpenIM admin network. -# Default: OPENIM_ADMIN_NETWORK_ADDRESS=172.28.0.14 -OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=172.28.0.14 - -# Address or hostname for the alertmanager network. -# Default: ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 -ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.14 -# =============================================== -# = Component Extension Configuration = -# =============================================== - -# ============ Component Extension Configuration ========== -# ----- ZooKeeper Configuration ----- -# Address or hostname for the ZooKeeper service. -# Default: ZOOKEEPER_ADDRESS=172.28.0.1 -ZOOKEEPER_ADDRESS=172.28.0.6 - -# Port for ZooKeeper service. -# Default: ZOOKEEPER_PORT=12181 -ZOOKEEPER_PORT=12181 - -# ----- MySQL Configuration ----- - -# Address or hostname for the MySQL service. -# Default: MYSQL_ADDRESS=172.28.0.1 -MYSQL_ADDRESS=172.28.0.2 - -# Port on which MySQL database service is running. -# Default: MYSQL_PORT=13306 -MYSQL_PORT=13306 - -# Password to authenticate with the MySQL database service. -# Default: MYSQL_PASSWORD=openIM123 -MYSQL_PASSWORD=openIM123 - -# ----- MongoDB Configuration ----- -# Address or hostname for the MongoDB service. -# Default: MONGO_ADDRESS=172.28.0.1 -MONGO_ADDRESS=172.28.0.3 - -# Port on which MongoDB service is running. -# Default: MONGO_PORT=37017 -MONGO_PORT=37017 - -# Username to authenticate with the MongoDB service. -# Default: MONGO_USERNAME=root -MONGO_USERNAME=root - -# Password to authenticate with the MongoDB service. -# Default: MONGO_PASSWORD=openIM123 -MONGO_PASSWORD=openIM123 - -# Name of the database in MongoDB to be used. -# Default: MONGO_DATABASE=openIM_v3 -MONGO_DATABASE=openIM_v3 - -# ----- Redis Configuration ----- -# Address or hostname for the Redis service. -# Default: REDIS_ADDRESS=172.28.0.1 -REDIS_ADDRESS=172.28.0.4 - -# Port on which Redis in-memory data structure store is running. -# Default: REDIS_PORT=16379 -REDIS_PORT=16379 - -# Password to authenticate with the Redis service. -# Default: REDIS_PASSWORD=openIM123 -REDIS_PASSWORD=openIM123 - -# ----- Kafka Configuration ----- -# Address or hostname for the Kafka service. -# Default: KAFKA_ADDRESS=172.28.0.1 -KAFKA_ADDRESS=172.28.0.5 - -# Port on which Kafka distributed streaming platform is running. -# Default: KAFKA_PORT=19092 -KAFKA_PORT=19094 - -# Topic in Kafka for storing the latest messages in Redis. -# Default: KAFKA_LATESTMSG_REDIS_TOPIC=latestMsgToRedis -KAFKA_LATESTMSG_REDIS_TOPIC=latestMsgToRedis - -# Topic in Kafka for pushing messages (e.g. notifications or updates). -# Default: KAFKA_MSG_PUSH_TOPIC=msgToPush -KAFKA_MSG_PUSH_TOPIC=msgToPush - -# Topic in Kafka for storing offline messages in MongoDB. -# Default: KAFKA_OFFLINEMSG_MONGO_TOPIC=offlineMsgToMongoMysql -KAFKA_OFFLINEMSG_MONGO_TOPIC=offlineMsgToMongoMysql - -# ----- MinIO Configuration ---- -# Address or hostname for the MinIO object storage service. -# Default: MINIO_ADDRESS=172.28.0.1 -MINIO_ADDRESS=172.28.0.7 - -# Port on which MinIO object storage service is running. -# Default: MINIO_PORT=10005 -MINIO_PORT=10005 - -# Access key to authenticate with the MinIO service. -# Default: MINIO_ACCESS_KEY=root -MINIO_ACCESS_KEY=root - -# Secret key corresponding to the access key for MinIO authentication. -# Default: MINIO_SECRET_KEY=openIM123 -MINIO_SECRET_KEY=openIM123 - -# ----- Prometheus Configuration ----- -# Address or hostname for the Prometheus service. -# Default: PROMETHEUS_ADDRESS=172.28.0.1 -PROMETHEUS_ADDRESS=172.28.0.11 - -# Port on which Prometheus service is running. -# Default: PROMETHEUS_PORT=19090 -PROMETHEUS_PORT=19090 - -# ----- Grafana Configuration ----- -# Address or hostname for the Grafana service. -# Default: GRAFANA_ADDRESS=172.28.0.1 -GRAFANA_ADDRESS=172.28.0.12 - -# Port on which Grafana service is running. -# Default: GRAFANA_PORT=3000 -GRAFANA_PORT=3000 - -# ====================================== -# ============ OpenIM Web =============== -# ====================================== - -# Path to the OpenIM web distribution. -# Default: OPENIM_WEB_DIST_PATH=/app/dist -OPENIM_WEB_DIST_PATH=/app/dist - -# Port on which OpenIM web service is running. -# Default: OPENIM_WEB_PORT=11001 -OPENIM_WEB_PORT=11001 - -# Address or hostname for the OpenIM web service. -# Default: OPENIM_WEB_ADDRESS=172.28.0.1 -OPENIM_WEB_ADDRESS=172.28.0.8 - -# ====================================== -# ========= OpenIM Server ============== -# ====================================== - -# Address or hostname for the OpenIM server. -# Default: OPENIM_SERVER_ADDRESS=172.28.0.1 -OPENIM_SERVER_ADDRESS=172.28.0.9 - -# Port for the OpenIM WebSockets. -# Default: OPENIM_WS_PORT=10001 -OPENIM_WS_PORT=10001 - -# Port for the OpenIM API. -# Default: API_OPENIM_PORT=10002 -API_OPENIM_PORT=10002 - - -# ====================================== -# ========== OpenIM Chat =============== -# ====================================== - -# Branch name for OpenIM chat. -# Default: CHAT_BRANCH=main -CHAT_BRANCH=main - -# Address or hostname for the OpenIM chat service. -# Default: OPENIM_CHAT_ADDRESS=172.28.0.1 -OPENIM_CHAT_ADDRESS=172.28.0.10 - -# Port for the OpenIM chat API. -# Default: OPENIM_CHAT_API_PORT=10008 -OPENIM_CHAT_API_PORT=10008 - -# Directory path for storing data files or related information for OpenIM chat. -# Default: OPENIM_CHAT_DATA_DIR=./openim-chat/main -OPENIM_CHAT_DATA_DIR=./openim-chat/main - - -# ====================================== -# ========== OpenIM Admin ============== -# ====================================== - -# Branch name for OpenIM server. -# Default: SERVER_BRANCH=main -SERVER_BRANCH=main - -# Port for the OpenIM admin API. -# Default: OPENIM_ADMIN_API_PORT=10009 -OPENIM_ADMIN_API_PORT=10009 - -# Port for the node exporter. -# Default: NODE_EXPORTER_PORT=19100 -NODE_EXPORTER_PORT=19100 - -# Port for the prometheus. -# Default: PROMETHEUS_PORT=19090 -PROMETHEUS_PORT=19090 - -# Port for the grafana. -# Default: GRAFANA_PORT=3000 -GRAFANA_PORT=3000 - -# Port for the admin front. -# Default: OPENIM_ADMIN_FRONT_PORT=11002 -OPENIM_ADMIN_FRONT_PORT=11002 - -# Port for the alertmanager. -# Default: ALERT_MANAGER_PORT=19093 -ALERT_MANAGER_PORT=19093 diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index b16d614f6..2f6d7fe05 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -22,6 +22,9 @@ on: # run e2e test every 4 hours - cron: 0 */4 * * * +env: + CALLBACK_ENABLE: true + jobs: build: name: Test @@ -70,9 +73,9 @@ jobs: - name: Docker Operations run: | - curl -o docker-compose.yml https://raw.githubusercontent.com/OpenIMSDK/openim-docker/main/example/basic-openim-server-dependency.yml + sudo make init sudo docker compose up -d - sudo sleep 60 + sudo sleep 20 - name: Module Operations run: | diff --git a/.github/workflows/opencommit.yml b/.github/workflows/opencommit.yml index 11bc00524..629a67aae 100644 --- a/.github/workflows/opencommit.yml +++ b/.github/workflows/opencommit.yml @@ -51,4 +51,5 @@ jobs: OCO_EMOJI: false OCO_MODEL: gpt-3.5-turbo-16k OCO_LANGUAGE: en - OCO_PROMPT_MODULE: conventional-commit \ No newline at end of file + OCO_PROMPT_MODULE: conventional-commit + continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/openimci.yml b/.github/workflows/openimci.yml index 2e4cc9e24..707369379 100644 --- a/.github/workflows/openimci.yml +++ b/.github/workflows/openimci.yml @@ -127,6 +127,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Run OpenIM make install start run: | + sudo make init && \ sudo make install execute-scripts: @@ -156,9 +157,9 @@ jobs: - name: Docker Operations run: | - curl -o docker-compose.yml https://raw.githubusercontent.com/OpenIMSDK/openim-docker/main/example/basic-openim-server-dependency.yml + sudo make init sudo docker compose up -d - sudo sleep 60 + sudo sleep 20 - name: Module Operations run: | @@ -195,4 +196,5 @@ jobs: - name: Test Docker Build run: | + sudo make init sudo make image \ No newline at end of file diff --git a/.gitignore b/.gitignore index fa1818e2b..6b65697d9 100644 --- a/.gitignore +++ b/.gitignore @@ -391,3 +391,4 @@ Sessionx.vim dist/ .env config/config.yaml +config/alertmanager.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index f738d4457..32639af7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,8 @@ WORKDIR ${SERVER_WORKDIR} # Copy scripts and binary files to the production image COPY --from=builder ${OPENIM_SERVER_BINDIR} /openim/openim-server/_output/bin -# COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts -# COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config +COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts +COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config +COPY --from=builder ${SERVER_WORKDIR}/deployments /openim/openim-server/deployments CMD ["/openim/openim-server/scripts/docker-start-all.sh"] diff --git a/config/alertmanager.yml b/config/alertmanager.yml deleted file mode 100644 index ee14b6464..000000000 --- a/config/alertmanager.yml +++ /dev/null @@ -1,32 +0,0 @@ -###################### AlertManager Configuration ###################### -# AlertManager configuration using environment variables -# -# Resolve timeout -# SMTP configuration for sending alerts -# Templates for email notifications -# Routing configurations for alerts -# Receiver configurations -global: - resolve_timeout: 5m - smtp_from: alert@openim.io - smtp_smarthost: smtp.163.com:465 - smtp_auth_username: alert@openim.io - smtp_auth_password: YOURAUTHPASSWORD - smtp_require_tls: false - smtp_hello: xxx监控告警 - -templates: - - /etc/alertmanager/email.tmpl - -route: - group_wait: 5s - group_interval: 5s - repeat_interval: 5m - receiver: email -receivers: - - name: email - email_configs: - - to: '{EMAIL_TO:-'alert@example.com'}' - html: '{{ template "email.to.html" . }}' - headers: { Subject: "[OPENIM-SERVER]Alarm" } - send_resolved: true diff --git a/config/config.yaml b/config/config.yaml deleted file mode 100644 index b17d10073..000000000 --- a/config/config.yaml +++ /dev/null @@ -1,409 +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. - -# ----------------------------------------------------------------- -# TODO: This config file is the template file -# --| source: deployments/templates/openim.yaml -# --| env: scripts/install/environment -# --| target: config/config.yaml -# ----------------------------------------------------------------- - -envs: - discovery: zookeeper - -###################### Zookeeper ###################### -# Zookeeper configuration -# It's not recommended to modify the schema -# -# Zookeeper address -# Zookeeper username -# Zookeeper password -zookeeper: - schema: openim - address: [ 172.28.0.1:12181 ] - username: '' - password: '' - -###################### Mysql ###################### -# MySQL configuration -# Currently, only single machine setup is supported -# -# Maximum number of open connections -# Maximum number of idle connections -# Maximum lifetime in seconds a connection can be reused -# Log level: 1=slient, 2=error, 3=warn, 4=info -# Slow query threshold in milliseconds -mysql: - address: [ 172.28.0.1:13306 ] - username: root - password: openIM123 - database: openIM_v3 - maxOpenConn: 1000 - maxIdleConn: 100 - maxLifeTime: 60 - logLevel: 4 - slowThreshold: 500 - -###################### Mongo ###################### -# MongoDB configuration -# If uri is not empty, it will be used directly -# -# MongoDB address for standalone setup, Mongos address for sharded cluster setup -# Default MongoDB database name -# Maximum connection pool size -mongo: - uri: '' - address: [ 172.28.0.1:37017 ] - database: openIM_v3 - username: root - password: openIM123 - maxPoolSize: 100 - -###################### Redis configuration information ###################### -# Redis configuration -# -# Username is required only for Redis version 6.0+ -redis: - address: [ 172.28.0.1:16379 ] - username: '' - password: openIM123 - -###################### Kafka configuration information ###################### -# Kafka configuration -# -# Kafka username -# Kafka password -# It's not recommended to modify this topic name -# Consumer group ID, it's not recommended to modify -kafka: - username: '' - password: '' - addr: [ 172.28.0.1:19094 ] - latestMsgToRedis: - topic: "latestMsgToRedis" - offlineMsgToMongo: - topic: "offlineMsgToMongoMysql" - msgToPush: - topic: "msgToPush" - consumerGroupID: - msgToRedis: redis - msgToMongo: mongo - msgToMySql: mysql - msgToPush: push - -###################### RPC configuration information ###################### -# RPC configuration -# -# IP address to register with zookeeper when starting RPC, the IP and corresponding rpcPort should be accessible by api/gateway -# Default listen IP is 0.0.0.0 -rpc: - registerIP: '' - listenIP: 0.0.0.0 - -###################### API configuration information ###################### -# API configuration -# -# API service port -# Default listen IP is 0.0.0.0 -api: - openImApiPort: [ 10002 ] - listenIP: 0.0.0.0 - -###################### Object configuration information ###################### -# Object storage configuration -# -# Use minio for object storage -# API URL should be accessible by the app -# It's not recommended to modify the bucket name -# Endpoint should be accessible by the app -# Session token -# Configuration for Tencent COS -# Configuration for Aliyun OSS -# apiURL is the address of the api, the access address of the app, use s3 must be configured -# minio.endpoint can be configured as an intranet address, -# minio.signEndpoint is minio public network address -object: - enable: "minio" - apiURL: "http://127.0.0.1:10002" - minio: - bucket: "openim" - endpoint: "http://172.28.0.1:10005" - accessKeyID: "root" - secretAccessKey: "openIM123" - sessionToken: '' - signEndpoint: "http://127.0.0.1:10005" - publicRead: false - cos: - bucketURL: https://temp-1252357374.cos.ap-chengdu.myqcloud.com - secretID: '' - secretKey: '' - sessionToken: '' - publicRead: false - oss: - endpoint: "https://oss-cn-chengdu.aliyuncs.com" - bucket: "demo-9999999" - bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com" - accessKeyID: '' - accessKeySecret: '' - sessionToken: '' - publicRead: false - kodo: - endpoint: "http://s3.cn-east-1.qiniucs.com" - bucket: "demo-9999999" - bucketURL: "http://your.domain.com" - accessKeyID: '' - accessKeySecret: '' - sessionToken: '' - publicRead: false -###################### RPC Port Configuration ###################### -# RPC service ports -# These ports are passed into the program by the script and are not recommended to modify -# For launching multiple programs, just fill in multiple ports separated by commas -# For example, [10110, 10111] -rpcPort: - openImUserPort: [ 10110 ] - openImFriendPort: [ 10120 ] - openImMessagePort: [ 10130 ] - openImGroupPort: [ 10150 ] - openImAuthPort: [ 10160 ] - openImPushPort: [ 10170 ] - openImConversationPort: [ 10180 ] - openImThirdPort: [ 10190 ] - -###################### RPC Register Name Configuration ###################### -# RPC service names for registration, it's not recommended to modify these -rpcRegisterName: - openImUserName: User - openImFriendName: Friend - openImMsgName: Msg - openImPushName: Push - openImMessageGatewayName: MessageGateway - openImGroupName: Group - openImAuthName: Auth - openImConversationName: Conversation - openImThirdName: Third - -###################### Log Configuration ###################### -# Log configuration -# -# Storage directory -# Log rotation time -# Maximum number of logs to retain -# Log level, 6 means all levels -# Whether to output to stdout -# Whether to output in json format -# Whether to include stack trace in logs -log: - storageLocation: ../logs/ - rotationTime: 24 - remainRotationCount: 2 - remainLogLevel: 6 - isStdout: false - isJson: false - withStack: false - -###################### Variables definition ###################### -# Long connection server configuration -# -# Websocket port for msg_gateway -# Maximum number of websocket connections -# Maximum length of websocket request package -# Websocket connection handshake timeout -longConnSvr: - openImWsPort: [ 10001 ] - websocketMaxConnNum: 100000 - openImMessageGatewayPort: [ 10140 ] - websocketMaxMsgLen: 4096 - websocketTimeout: 10 - -# Push notification service configuration -# -# Use GeTui for push notifications -# GeTui offline push configuration -# FCM offline push configuration -# Account file, place it in the config directory -# JPush configuration, modify these after applying in JPush backend -push: - enable: getui - geTui: - pushUrl: "https://restapi.getui.com/v2/$appId" - masterSecret: '' - appKey: '' - intent: '' - channelID: '' - channelName: '' - fcm: - serviceAccount: "x.json" - jpns: - appKey: '' - masterSecret: '' - pushUrl: '' - pushIntent: '' - -# App manager configuration -# -# Built-in app manager user IDs -# Built-in app manager nicknames -manager: - userID: [ "openIM123456", "openIM654321", "openIMAdmin" ] - nickname: [ "system1", "system2", "system3" ] - -# Multi-platform login policy -# For each platform(Android, iOS, Windows, Mac, web), only one can be online at a time -multiLoginPolicy: 1 - -# Whether to store messages in MySQL, messages in MySQL are only used for management background -chatPersistenceMysql: true - -# Message cache timeout in seconds, it's not recommended to modify -msgCacheTimeout: 86400 - -# Whether to enable read receipts for group chat -groupMessageHasReadReceiptEnable: true - -# Whether to enable read receipts for single chat -singleMessageHasReadReceiptEnable: true - -# MongoDB offline message retention period in days -retainChatRecords: 365 - -# Schedule to clear expired messages(older than retainChatRecords days) in MongoDB every Wednesday at 2am -# This deletion is just for cleaning up disk usage according to previous configuration retainChatRecords, no notification will be sent -chatRecordsClearTime: "0 2 * * 3" - -# Schedule to auto delete messages every day at 2am -# This deletion is for messages that have been retained for more than msg_destruct_time (seconds) in the conversation field -msgDestructTime: "0 2 * * *" - -# Secret key -secret: openIM123 - -# Token policy -# -# Token expiration period in days -tokenPolicy: - expire: 90 - -# Message verification policy -# -# Whether to verify friendship when sending messages -messageVerify: - friendVerify: false - -# iOS push notification configuration -# -# iOS push notification sound -# Whether to count badge -# Whether it's production environment -iosPush: - pushSound: "xxx" - badgeCount: true - production: false - -###################### Third-party service configuration ###################### -# Callback configuration -# -# Callback URL -# Whether to enable this callback event -# Timeout in seconds -# Whether to continue execution if callback fails -callback: - url: - beforeSendSingleMsg: - enable: false - timeout: 5 - failedContinue: true - afterSendSingleMsg: - enable: false - timeout: 5 - beforeSendGroupMsg: - enable: false - timeout: 5 - failedContinue: true - afterSendGroupMsg: - enable: false - timeout: 5 - msgModify: - enable: false - timeout: 5 - failedContinue: true - userOnline: - enable: false - timeout: 5 - userOffline: - enable: false - timeout: 5 - userKickOff: - enable: false - timeout: 5 - offlinePush: - enable: false - timeout: 5 - failedContinue: true - onlinePush: - enable: false - timeout: 5 - failedContinue: true - superGroupOnlinePush: - enable: false - timeout: 5 - failedContinue: true - beforeAddFriend: - enable: false - timeout: 5 - failedContinue: true - beforeUpdateUserInfo: - enable: false - timeout: 5 - failedContinue: true - beforeCreateGroup: - enable: false - timeout: 5 - failedContinue: true - beforeMemberJoinGroup: - enable: false - timeout: 5 - failedContinue: true - beforeInviteUserToGroup: - enable: true - timeout: 5 - failedContinue: true - beforeSetGroupMemberInfo: - enable: false - timeout: 5 - failedContinue: true - setMessageReactionExtensions: - enable: false - timeout: 5 - failedContinue: true - -###################### Prometheus ###################### -# Prometheus configuration for various services -# The number of Prometheus ports per service needs to correspond to rpcPort -# The number of ports needs to be consistent with msg_transfer_service_num in script/path_info.sh -prometheus: - enable: false - prometheusUrl: "https://openim.prometheus" - apiPrometheusPort: [20100] - userPrometheusPort: [ 20110 ] - friendPrometheusPort: [ 20120 ] - messagePrometheusPort: [ 20130 ] - messageGatewayPrometheusPort: [ 20140 ] - groupPrometheusPort: [ 20150 ] - authPrometheusPort: [ 20160 ] - pushPrometheusPort: [ 20170 ] - conversationPrometheusPort: [ 20230 ] - rtcPrometheusPort: [ 21300 ] - thirdPrometheusPort: [ 21301 ] - messageTransferPrometheusPort: [ 21400, 21401, 21402, 21403 ] # List of ports diff --git a/deployments/templates/env_template.yaml b/deployments/templates/env_template.yaml index 954b2cf65..0ace53286 100644 --- a/deployments/templates/env_template.yaml +++ b/deployments/templates/env_template.yaml @@ -17,8 +17,8 @@ # ====================================== # The user for authentication or system operations. -# Default: USER=root -USER=${USER} +# Default: OPENIM_USER=root +USER=${OPENIM_USER} # Password associated with the specified user for authentication. # Default: PASSWORD=openIM123 @@ -58,58 +58,20 @@ DOCKER_BRIDGE_GATEWAY=${DOCKER_BRIDGE_GATEWAY} # Address or hostname for the MySQL network. # Default: MYSQL_NETWORK_ADDRESS=172.28.0.2 MYSQL_NETWORK_ADDRESS=${MYSQL_NETWORK_ADDRESS} - -# Address or hostname for the MongoDB network. -# Default: MONGO_NETWORK_ADDRESS=172.28.0.3 MONGO_NETWORK_ADDRESS=${MONGO_NETWORK_ADDRESS} - -# Address or hostname for the Redis network. -# Default: REDIS_NETWORK_ADDRESS=172.28.0.4 REDIS_NETWORK_ADDRESS=${REDIS_NETWORK_ADDRESS} - -# Address or hostname for the Kafka network. -# Default: KAFKA_NETWORK_ADDRESS=172.28.0.5 KAFKA_NETWORK_ADDRESS=${KAFKA_NETWORK_ADDRESS} - -# Address or hostname for the ZooKeeper network. -# Default: ZOOKEEPER_NETWORK_ADDRESS=172.28.0.6 ZOOKEEPER_NETWORK_ADDRESS=${ZOOKEEPER_NETWORK_ADDRESS} - -# Address or hostname for the MinIO network. -# Default: MINIO_NETWORK_ADDRESS=172.28.0.7 MINIO_NETWORK_ADDRESS=${MINIO_NETWORK_ADDRESS} - -# Address or hostname for the OpenIM web network. -# Default: OPENIM_WEB_NETWORK_ADDRESS=172.28.0.8 OPENIM_WEB_NETWORK_ADDRESS=${OPENIM_WEB_NETWORK_ADDRESS} - -# Address or hostname for the OpenIM server network. -# Default: OPENIM_SERVER_NETWORK_ADDRESS=172.28.0.9 OPENIM_SERVER_NETWORK_ADDRESS=${OPENIM_SERVER_NETWORK_ADDRESS} - -# Address or hostname for the OpenIM chat network. -# Default: OPENIM_CHAT_NETWORK_ADDRESS=172.28.0.10 OPENIM_CHAT_NETWORK_ADDRESS=${OPENIM_CHAT_NETWORK_ADDRESS} - -# Address or hostname for the Prometheus network. -# Default: PROMETHEUS_NETWORK_ADDRESS=172.28.0.11 PROMETHEUS_NETWORK_ADDRESS=${PROMETHEUS_NETWORK_ADDRESS} - -# Address or hostname for the Grafana network. -# Default: GRAFANA_NETWORK_ADDRESS=172.28.0.12 GRAFANA_NETWORK_ADDRESS=${GRAFANA_NETWORK_ADDRESS} - -# Address or hostname for the node_exporter network. -# Default: NODE_EXPORTER_NETWORK_ADDRESS=172.28.0.13 NODE_EXPORTER_NETWORK_ADDRESS=${NODE_EXPORTER_NETWORK_ADDRESS} - -# Address or hostname for the OpenIM admin network. -# Default: OPENIM_ADMIN_NETWORK_ADDRESS=172.28.0.14 OPENIM_ADMIN_FRONT_NETWORK_ADDRESS=${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS} - -# Address or hostname for the alertmanager network. -# Default: ALERT_MANAGER_NETWORK_ADDRESS=172.28.0.15 ALERT_MANAGER_NETWORK_ADDRESS=${ALERT_MANAGER_NETWORK_ADDRESS} + # =============================================== # = Component Extension Configuration = # =============================================== diff --git a/install.sh b/install.sh index 9318c33ba..7ff0f8739 100755 --- a/install.sh +++ b/install.sh @@ -63,7 +63,7 @@ PROXY= GITHUB_TOKEN= # Default user is "root". If you need to modify it, uncomment and replace accordingly. -# USER=root +# OPENIM_USER=root # Default password for redis, mysql, mongo, as well as accessSecret in config/config.yaml. # Remember, it should be a combination of 8 or more numbers and letters. If you want to set a different password, uncomment and replace "openIM123". @@ -244,10 +244,10 @@ function download_source_code() { function set_openim_env() { warn "This command can only be executed once. It will modify the component passwords in docker-compose based on the PASSWORD variable in .env, and modify the component passwords in config/config.yaml. If the password in .env changes, you need to first execute docker-compose down; rm components -rf and then execute this command." # Set default values for user input - # If the USER environment variable is not set, it defaults to 'root' - if [ -z "$USER" ]; then - USER="root" - debug "USER is not set. Defaulting to 'root'." + # If the OPENIM_USER environment variable is not set, it defaults to 'root' + if [ -z "$OPENIM_USER" ]; then + OPENIM_USER="root" + debug "OPENIM_USER is not set. Defaulting to 'root'." fi # If the PASSWORD environment variable is not set, it defaults to 'openIM123' @@ -321,7 +321,7 @@ function cmd_help() { function parseinput() { # set default values - # USER=root + # OPENIM_USER=root # PASSWORD=openIM123 # ENDPOINT=http://127.0.0.1:10005 # API=http://127.0.0.1:10002/object/ @@ -347,7 +347,7 @@ function parseinput() { ;; -u|--user) shift - USER=$1 + OPENIM_USER=$1 ;; -p|--password) shift diff --git a/install_guide.sh b/install_guide.sh index b10ab2edd..c4323d6a8 100755 --- a/install_guide.sh +++ b/install_guide.sh @@ -110,7 +110,7 @@ install_docker_compose() { read NEW_USER is_empty $NEW_USER if [ $? -eq 0 ]; then - USER=$NEW_USER + OPENIM_USER=$NEW_USER fi echo "Please input the password, default is openIM123, press enter to use default" @@ -131,12 +131,12 @@ install_docker_compose() { fi set -e export MINIO_ENDPOINT - export USER + export OPENIM_USER export PASSWORD export DATA_DIR cat < .env -USER=${USER} +OPENIM_USER=${OPENIM_USER} PASSWORD=${PASSWORD} MINIO_ENDPOINT=${MINIO_ENDPOINT} DATA_DIR=${DATA_DIR} diff --git a/scripts/init-pwd.sh b/scripts/init-pwd.sh deleted file mode 100755 index 5e2e162aa..000000000 --- a/scripts/init-pwd.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -#Include shell font styles and some basic information -SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) -OPENIM_ROOT=$(dirname "${SCRIPTS_ROOT}")/.. - -#Include shell font styles and some basic information -source $SCRIPTS_ROOT/lib/init.sh -source $SCRIPTS_ROOT/path_info.sh - -cd $SCRIPTS_ROOT - -source $OPENIM_ROOT/.env - -# Check if PASSWORD only contains letters and numbers -if [[ "$PASSWORD" =~ ^[a-zA-Z0-9]+$ ]] -then - echo "PASSWORD is valid." -else - echo "ERR: PASSWORD should only contain letters and numbers. " $PASSWORD - exit -fi - -echo "" -echo -e "===> ${PURPLE_PREFIX} you user is:$USER ${COLOR_SUFFIX}" -echo -e "===> ${PURPLE_PREFIX} you password is:$PASSWORD ${COLOR_SUFFIX}" -echo -e "===> ${PURPLE_PREFIX} you minio endpoint is:$MINIO_ENDPOINT ${COLOR_SUFFIX}" -echo -e "===> ${PURPLE_PREFIX} you api url is:$API_URL ${COLOR_SUFFIX}" -echo "" - -# Specify the config file -config_file="${OPENIM_ROOT}"/config/config.yaml - -# Load variables from .env file -source "${OPENIM_ROOT}"/.env - -# Replace the password and username field for mysql -sed -i "/mysql:/,/database:/ s/password:.*/password: $PASSWORD/" $config_file -sed -i "/mysql:/,/database:/ s/username:.*/username: $USER/" $config_file - -# Replace the password and username field for mongo -sed -i "/mongo:/,/maxPoolSize:/ s/password:.*/password: $PASSWORD/" $config_file -sed -i "/mongo:/,/maxPoolSize:/ s/username:.*/username: $USER/" $config_file - -# Replace the password field for redis -sed -i '/redis:/,/password:/s/password: .*/password: '${PASSWORD}'/' $config_file - -# Replace accessKeyID and secretAccessKey for minio -sed -i "/minio:/,/isDistributedMod:/ s/accessKeyID:.*/accessKeyID: $USER/" $config_file -sed -i "/minio:/,/isDistributedMod:/ s/secretAccessKey:.*/secretAccessKey: $PASSWORD/" $config_file -sed -i '/minio:/,/endpoint:/s|endpoint: .*|endpoint: '${MINIO_ENDPOINT}'|' $config_file -sed -i '/object:/,/apiURL:/s|apiURL: .*|apiURL: '${API_URL}'|' $config_file - - -# Replace secret for token -sed -i "s/secret: .*/secret: $PASSWORD/" $config_file From df7bfc67b666824329388718c0a61b7d6c64c8bd Mon Sep 17 00:00:00 2001 From: withchao <993506633@qq.com> Date: Thu, 30 Nov 2023 20:18:12 +0800 Subject: [PATCH 17/18] merge main --- internal/rpc/group/group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 191a481a8..1254f2dd8 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -1196,7 +1196,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou } s.Notification.GroupDismissedNotification(ctx, tips) } - membersID, err := s.GroupDatabase.FindGroupMemberUserID(ctx, group.GroupID) + membersID, err := s.db.FindGroupMemberUserID(ctx, group.GroupID) if err != nil { return nil, err } From 768e6bc758d75bcd77bee3fce335853246c62fee Mon Sep 17 00:00:00 2001 From: withchao <993506633@qq.com> Date: Thu, 30 Nov 2023 20:46:52 +0800 Subject: [PATCH 18/18] merge main --- go.mod | 2 +- internal/msgtransfer/init.go | 28 +- .../msgtransfer/persistent_msg_handler.go | 119 ------- internal/rpc/conversation/conversaion.go | 14 +- internal/rpc/friend/black.go | 23 +- internal/rpc/friend/friend.go | 43 +-- internal/rpc/group/group.go | 33 +- internal/rpc/third/log.go | 10 +- internal/rpc/third/third.go | 14 +- internal/rpc/user/user.go | 14 +- internal/tools/msg.go | 29 +- pkg/common/db/cache/group.go | 12 +- pkg/common/db/cache/msg.go | 67 +--- pkg/common/db/cache/msg_test.go | 47 --- pkg/common/db/cache/user.go | 3 +- pkg/common/db/controller/black.go | 17 +- pkg/common/db/controller/chatlog.go | 37 -- pkg/common/db/controller/conversation.go | 7 +- pkg/common/db/controller/friend.go | 176 +++------- pkg/common/db/controller/group.go | 14 +- pkg/common/db/controller/msg.go | 60 ++-- pkg/common/db/controller/third.go | 15 +- pkg/common/db/controller/user.go | 48 +-- pkg/common/db/mgo/black.go | 91 +++++ pkg/common/db/{newmgo => mgo}/conversation.go | 73 ++-- pkg/common/db/{newmgo => mgo}/friend.go | 102 ++---- pkg/common/db/mgo/friend_request.go | 99 ++++++ pkg/common/db/{newmgo => mgo}/group.go | 79 ++++- pkg/common/db/{newmgo => mgo}/group_member.go | 43 ++- .../db/{newmgo => mgo}/group_request.go | 38 ++- pkg/common/db/mgo/log.go | 70 ++++ pkg/common/db/{newmgo => mgo}/object.go | 30 +- pkg/common/db/{newmgo => mgo}/user.go | 90 +++-- pkg/common/db/newmgo/friend_request.go | 48 --- pkg/common/db/newmgo/log.go | 49 --- pkg/common/db/newmgo/mgotool/tool.go | 198 ----------- pkg/common/db/relation/black_model.go | 111 ------ pkg/common/db/relation/chat_log_model.go | 63 ---- pkg/common/db/relation/conversation_model.go | 244 ------------- pkg/common/db/relation/doc.go | 15 - pkg/common/db/relation/friend_model.go | 193 ----------- .../db/relation/friend_request_model.go | 154 --------- pkg/common/db/relation/group_member_model.go | 198 ----------- pkg/common/db/relation/group_model.go | 106 ------ pkg/common/db/relation/group_request_model.go | 119 ------- pkg/common/db/relation/log_model.go | 49 --- pkg/common/db/relation/meta_db.go | 38 --- pkg/common/db/relation/mysql_init.go | 157 --------- pkg/common/db/relation/mysql_init_test.go | 121 ------- pkg/common/db/relation/object_model.go | 54 --- pkg/common/db/relation/user_model.go | 138 -------- pkg/common/db/s3/kodo/internal.go | 1 - pkg/common/db/s3/kodo/kodo.go | 323 ------------------ pkg/common/db/s3/oss/oss.go | 0 pkg/common/db/table/relation/black.go | 26 +- pkg/common/db/table/relation/chatlog.go | 51 --- pkg/common/db/table/relation/conversation.go | 32 +- pkg/common/db/table/relation/doc.go | 15 - pkg/common/db/table/relation/friend.go | 44 +-- .../db/table/relation/friend_request.go | 34 +- pkg/common/db/table/relation/group.go | 27 +- pkg/common/db/table/relation/group_member.go | 23 +- pkg/common/db/table/relation/group_request.go | 23 +- pkg/common/db/table/relation/log.go | 23 +- pkg/common/db/table/relation/object.go | 20 -- pkg/common/db/table/relation/user.go | 3 +- pkg/common/db/table/relation/utils.go | 5 +- pkg/common/db/tx/auto.go | 19 -- pkg/common/db/tx/invalid.go | 16 - pkg/common/db/tx/tx.go | 28 -- pkg/common/db/unrelation/mongo.go | 0 pkg/common/db/unrelation/msg.go | 0 pkg/common/db/unrelation/user.go | 0 73 files changed, 820 insertions(+), 3495 deletions(-) delete mode 100644 internal/msgtransfer/persistent_msg_handler.go delete mode 100644 pkg/common/db/controller/chatlog.go create mode 100644 pkg/common/db/mgo/black.go rename pkg/common/db/{newmgo => mgo}/conversation.go (70%) rename pkg/common/db/{newmgo => mgo}/friend.go (63%) create mode 100644 pkg/common/db/mgo/friend_request.go rename pkg/common/db/{newmgo => mgo}/group.go (50%) rename pkg/common/db/{newmgo => mgo}/group_member.go (74%) rename pkg/common/db/{newmgo => mgo}/group_request.go (64%) create mode 100644 pkg/common/db/mgo/log.go rename pkg/common/db/{newmgo => mgo}/object.go (64%) rename pkg/common/db/{newmgo => mgo}/user.go (50%) delete mode 100644 pkg/common/db/newmgo/friend_request.go delete mode 100644 pkg/common/db/newmgo/log.go delete mode 100644 pkg/common/db/newmgo/mgotool/tool.go delete mode 100644 pkg/common/db/relation/black_model.go delete mode 100644 pkg/common/db/relation/chat_log_model.go delete mode 100644 pkg/common/db/relation/conversation_model.go delete mode 100644 pkg/common/db/relation/doc.go delete mode 100644 pkg/common/db/relation/friend_model.go delete mode 100644 pkg/common/db/relation/friend_request_model.go delete mode 100644 pkg/common/db/relation/group_member_model.go delete mode 100644 pkg/common/db/relation/group_model.go delete mode 100644 pkg/common/db/relation/group_request_model.go delete mode 100644 pkg/common/db/relation/log_model.go delete mode 100644 pkg/common/db/relation/meta_db.go delete mode 100644 pkg/common/db/relation/mysql_init.go delete mode 100644 pkg/common/db/relation/mysql_init_test.go delete mode 100644 pkg/common/db/relation/object_model.go delete mode 100644 pkg/common/db/relation/user_model.go delete mode 100644 pkg/common/db/s3/kodo/internal.go delete mode 100644 pkg/common/db/s3/kodo/kodo.go mode change 100755 => 100644 pkg/common/db/s3/oss/oss.go delete mode 100644 pkg/common/db/table/relation/chatlog.go delete mode 100644 pkg/common/db/table/relation/doc.go delete mode 100644 pkg/common/db/tx/auto.go delete mode 100644 pkg/common/db/tx/invalid.go delete mode 100644 pkg/common/db/tx/tx.go mode change 100755 => 100644 pkg/common/db/unrelation/mongo.go mode change 100755 => 100644 pkg/common/db/unrelation/msg.go mode change 100755 => 100644 pkg/common/db/unrelation/user.go diff --git a/go.mod b/go.mod index ae884a5aa..52b1bb4e9 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require github.com/google/uuid v1.3.1 require ( github.com/IBM/sarama v1.41.3 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/go-redis/redis v6.15.9+incompatible github.com/go-sql-driver/mysql v1.7.1 diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 8436317ee..a8d10799f 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -17,21 +17,20 @@ package msgtransfer import ( "errors" "fmt" + "log" + "net/http" + "sync" + "github.com/OpenIMSDK/tools/mw" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "google.golang.org/grpc" "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/db/cache" "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" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" @@ -39,20 +38,12 @@ import ( ) type MsgTransfer struct { - persistentCH *PersistentConsumerHandler // 聊天记录持久化到mysql的消费者 订阅的topic: ws2ms_chat historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topic:ws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送, 发消息到msg_to_mongo topic持久化 historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息,以及处理删除通知消息删除的 订阅的topic: msg_to_mongo // modifyCH *ModifyMsgConsumerHandler // 负责消费修改消息通知的consumer, 订阅的topic: msg_to_modify } 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() if err != nil { return err @@ -78,21 +69,16 @@ func StartTransfer(prometheusPort int) error { client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) msgModel := cache.NewMsgCacheModel(rdb) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) - msgMysModel := relation.NewChatLogGorm(db) - chatLogDatabase := controller.NewChatLogDatabase(msgMysModel) msgDatabase := controller.NewCommonMsgDatabase(msgDocModel, msgModel) conversationRpcClient := rpcclient.NewConversationRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client) - msgTransfer := NewMsgTransfer(chatLogDatabase, msgDatabase, &conversationRpcClient, &groupRpcClient) + msgTransfer := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) return msgTransfer.Start(prometheusPort) } -func NewMsgTransfer(chatLogDatabase controller.ChatLogDatabase, - msgDatabase controller.CommonMsgDatabase, - conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, -) *MsgTransfer { +func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) *MsgTransfer { return &MsgTransfer{ - persistentCH: NewPersistentConsumerHandler(chatLogDatabase), historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), + historyCH: NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient), historyMongoCH: NewOnlineHistoryMongoConsumerHandler(msgDatabase), } } diff --git a/internal/msgtransfer/persistent_msg_handler.go b/internal/msgtransfer/persistent_msg_handler.go deleted file mode 100644 index d105de2fe..000000000 --- a/internal/msgtransfer/persistent_msg_handler.go +++ /dev/null @@ -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 -} diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index 12e3e96fd..88c9ff7ff 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -17,8 +17,10 @@ package conversation import ( "context" "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" "google.golang.org/grpc" @@ -53,11 +55,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - tx, err := tx2.NewAuto(context.Background(), mongo.GetClient()) - if err != nil { - return err - } - conversationDB, err := newmgo.NewConversationMongo(mongo.GetDatabase()) + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) if err != nil { return err } @@ -66,7 +64,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e pbconversation.RegisterConversationServer(server, &conversationServer{ conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), 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 } diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index fee2d5480..54cdbb2cc 100644 --- a/internal/rpc/friend/black.go +++ b/internal/rpc/friend/black.go @@ -27,19 +27,11 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) -func (s *friendServer) GetPaginationBlacks( - ctx context.Context, - req *pbfriend.GetPaginationBlacksReq, -) (resp *pbfriend.GetPaginationBlacksResp, err error) { +func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *pbfriend.GetPaginationBlacksReq) (resp *pbfriend.GetPaginationBlacksResp, err error) { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err } - var pageNumber, showNumber int32 - if req.Pagination != nil { - pageNumber = req.Pagination.PageNumber - showNumber = req.Pagination.ShowNumber - } - blacks, total, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, pageNumber, showNumber) + total, blacks, err := s.blackDatabase.FindOwnerBlacks(ctx, req.UserID, req.Pagination) if err != nil { return nil, err } @@ -63,10 +55,7 @@ func (s *friendServer) IsBlack(ctx context.Context, req *pbfriend.IsBlackReq) (* return resp, nil } -func (s *friendServer) RemoveBlack( - ctx context.Context, - req *pbfriend.RemoveBlackReq, -) (*pbfriend.RemoveBlackResp, error) { +func (s *friendServer) RemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) (*pbfriend.RemoveBlackResp, error) { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { return nil, err } @@ -74,9 +63,6 @@ func (s *friendServer) RemoveBlack( return nil, err } s.notificationSender.BlackDeletedNotification(ctx, req) - if err := CallbackAfterRemoveBlack(ctx, req); err != nil { - return nil, err - } return &pbfriend.RemoveBlackResp{}, nil } @@ -88,9 +74,6 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq) if err != nil { return nil, err } - if err := CallbackBeforeAddBlack(ctx, req); err != nil { - return nil, err - } black := relation.BlackModel{ OwnerUserID: req.OwnerUserID, BlockUserID: req.BlackUserID, diff --git a/internal/rpc/friend/friend.go b/internal/rpc/friend/friend.go index 5c80d7f00..a8db9f721 100644 --- a/internal/rpc/friend/friend.go +++ b/internal/rpc/friend/friend.go @@ -17,6 +17,8 @@ package friend import ( "context" + "github.com/OpenIMSDK/tools/tx" + "github.com/OpenIMSDK/protocol/sdkws" "github.com/openimsdk/open-im-server/v3/pkg/authverify" @@ -32,12 +34,11 @@ import ( pbfriend "github.com/OpenIMSDK/protocol/friend" registry "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/tx" "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/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" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "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 } - friendMongoDB, err := newmgo.NewFriendMongo(mongo.GetDatabase()) + friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase()) if err != nil { return err } - friendRequestMongoDB, err := newmgo.NewFriendRequestMongo(mongo.GetDatabase()) + friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase()) if err != nil { return err } - blackMongoDB, err := newmgo.NewBlackMongo(mongo.GetDatabase()) + blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase()) if err != nil { return err } @@ -89,7 +90,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { &msgRpcClient, notification.WithRpcFunc(userRpcClient.GetUsersInfo), ) - // Register Friend server with refactored MongoDB and Redis integrations pbfriend.RegisterFriendServer(server, &friendServer{ friendDatabase: controller.NewFriendDatabase( @@ -311,15 +311,12 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, } // ok 获取接收到的好友申请(即别人主动申请的). -func (s *friendServer) GetPaginationFriendsApplyTo( - ctx context.Context, - req *pbfriend.GetPaginationFriendsApplyToReq, -) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { +func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { 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 { return nil, err } @@ -333,16 +330,13 @@ func (s *friendServer) GetPaginationFriendsApplyTo( } // ok 获取主动发出去的好友申请列表. -func (s *friendServer) GetPaginationFriendsApplyFrom( - ctx context.Context, - req *pbfriend.GetPaginationFriendsApplyFromReq, -) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { +func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetPaginationFriendsApplyFromResp{} if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { 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 { return nil, err } @@ -355,10 +349,7 @@ func (s *friendServer) GetPaginationFriendsApplyFrom( } // ok. -func (s *friendServer) IsFriend( - ctx context.Context, - req *pbfriend.IsFriendReq, -) (resp *pbfriend.IsFriendResp, err error) { +func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.IsFriendResp{} resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) @@ -368,15 +359,12 @@ func (s *friendServer) IsFriend( return resp, nil } -func (s *friendServer) GetPaginationFriends( - ctx context.Context, - req *pbfriend.GetPaginationFriendsReq, -) (resp *pbfriend.GetPaginationFriendsResp, err error) { +func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { 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 { return nil, err } @@ -389,10 +377,7 @@ func (s *friendServer) GetPaginationFriends( return resp, nil } -func (s *friendServer) GetFriendIDs( - ctx context.Context, - req *pbfriend.GetFriendIDsReq, -) (resp *pbfriend.GetFriendIDsResp, err error) { +func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { return nil, err diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 1254f2dd8..5992ed031 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,18 +17,19 @@ package group import ( "context" "fmt" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "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" + "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "math/big" "math/rand" "strconv" "strings" "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/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/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" ) 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() if err != nil { return err @@ -74,27 +67,23 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - groupDB, err := newmgo.NewGroupMongo(mongo.GetDatabase()) + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) if err != nil { return err } - groupMemberDB, err := newmgo.NewGroupMember(mongo.GetDatabase()) + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) if err != nil { return err } - groupRequestDB, err := newmgo.NewGroupRequestMgo(mongo.GetDatabase()) + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) if err != nil { return err } userRpcClient := rpcclient.NewUserRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client) - tx, err := tx2.NewAuto(context.Background(), mongo.GetClient()) - if err != nil { - return err - } 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.User = userRpcClient gs.Notification = notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index 30d95e26b..57d4f536e 100644 --- a/internal/rpc/third/log.go +++ b/internal/rpc/third/log.go @@ -32,11 +32,11 @@ func genLogID() string { } 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) platform := constant.PlatformID2Name[int(req.Platform)] for _, fileURL := range req.FileURLs { - log := relationtb.Log{ + log := relationtb.LogModel{ Version: req.Version, SystemType: req.SystemType, Platform: platform, @@ -57,7 +57,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) } } 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) } @@ -92,8 +92,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq) return &third.DeleteLogsResp{}, nil } -func dbToPbLogInfos(logs []*relationtb.Log) []*third.LogInfo { - db2pbForLogInfo := func(log *relationtb.Log) *third.LogInfo { +func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo { + db2pbForLogInfo := func(log *relationtb.LogModel) *third.LogInfo { return &third.LogInfo{ Filename: log.FileName, UserID: log.UserID, diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index f285790b3..7a63d3526 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,17 +17,17 @@ package third import ( "context" "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" "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/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/oss" + "google.golang.org/grpc" "github.com/OpenIMSDK/protocol/third" @@ -44,11 +44,11 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - logdb, err := newmgo.NewLogMongo(mongo.GetDatabase()) + logdb, err := mgo.NewLogMongo(mongo.GetDatabase()) if err != nil { return err } - s3db, err := newmgo.NewS3Mongo(mongo.GetDatabase()) + s3db, err := mgo.NewS3Mongo(mongo.GetDatabase()) if err != nil { return err } @@ -77,8 +77,6 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e o, err = cos.NewCos() case "oss": o, err = oss.NewOSS() - case "kodo": - o, err = kodo.NewKodo() default: err = fmt.Errorf("invalid object enable: %s", enable) } diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 69d7bd318..176bc91a9 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -17,11 +17,13 @@ package user import ( "context" "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" "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/sdkws" "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 { users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin}) } - userDB, err := newmgo.NewUserMongo(mongo.GetDatabase()) - if err != nil { - return err - } - tx, err := tx2.NewAuto(context.Background(), mongo.GetClient()) + userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) if err != nil { return err } cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) 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) groupRpcClient := rpcclient.NewGroupRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) diff --git a/internal/tools/msg.go b/internal/tools/msg.go index bf0231786..97bb2988e 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -17,11 +17,13 @@ package tools import ( "context" "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" + "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" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -78,43 +80,40 @@ func InitMsgTool() (*MsgTool, error) { return nil, err } discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) - userDB, err := newmgo.NewUserMongo(mongo.GetDatabase()) - if err != nil { - return nil, err - } - tx, err := tx2.NewAuto(context.Background(), mongo.GetClient()) + userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) if err != nil { return nil, err } msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) + ctxTx := tx.NewMongo(mongo.GetClient()) userDatabase := controller.NewUserDatabase( userDB, cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), - tx, + ctxTx, userMongoDB, ) - groupDB, err := newmgo.NewGroupMongo(mongo.GetDatabase()) + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) if err != nil { return nil, err } - groupMemberDB, err := newmgo.NewGroupMember(mongo.GetDatabase()) + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) if err != nil { return nil, err } - groupRequestDB, err := newmgo.NewGroupRequestMgo(mongo.GetDatabase()) + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) if err != nil { return nil, err } - conversationDB, err := newmgo.NewConversationMongo(mongo.GetDatabase()) + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) if err != nil { return nil, err } - groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx, nil) + groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, ctxTx, nil) conversationDatabase := controller.NewConversationDatabase( conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), - tx, + ctxTx, ) msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index b45cfd091..603d8e534 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -17,11 +17,12 @@ package cache import ( "context" "fmt" - "github.com/OpenIMSDK/protocol/constant" - "github.com/OpenIMSDK/tools/errs" "strconv" "time" + "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "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) if err != nil { return 0, nil, err diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index 45dee3950..5cd3cb22c 100644 --- a/pkg/common/db/cache/msg.go +++ b/pkg/common/db/cache/msg.go @@ -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 { - var retErr error - 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 - } - } + return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey) } 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) { - var retErr error - 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 - } - } + return c.getSeq(ctx, conversationID, c.getMaxSeqKey) } 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 { - var ( - cursor uint64 - keys []string - err error - - key = c.allMessageCacheKey(conversationID) - ) - - for { - // 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 { + vals, err := c.rdb.Keys(ctx, c.allMessageCacheKey(conversationID)).Result() + if errors.Is(err, redis.Nil) { + return nil + } + if err != nil { + return errs.Wrap(err) + } + for _, v := range vals { + if err := c.rdb.Del(ctx, v).Err(); err != nil { 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 { diff --git a/pkg/common/db/cache/msg_test.go b/pkg/common/db/cache/msg_test.go index a5be018ed..3fddf5965 100644 --- a/pkg/common/db/cache/msg_test.go +++ b/pkg/common/db/cache/msg_test.go @@ -385,50 +385,3 @@ func testParallelDeleteMessagesMix(t *testing.T, cid string, seqs []int64, input 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)) -} diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index e0f22b2f7..979bd06e4 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -18,11 +18,12 @@ import ( "context" "encoding/json" "errors" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "hash/crc32" "strconv" "time" + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/protocol/constant" diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index 70e942a77..e68d06b01 100644 --- a/pkg/common/db/controller/black.go +++ b/pkg/common/db/controller/black.go @@ -17,6 +17,8 @@ package controller import ( "context" + "github.com/OpenIMSDK/tools/pagination" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/utils" @@ -30,12 +32,7 @@ type BlackDatabase interface { // Delete 删除黑名单 Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) // FindOwnerBlacks 获取黑名单列表 - FindOwnerBlacks( - 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) + FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, 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(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 获取黑名单列表. -func (b *blackDatabase) FindOwnerBlacks( - ctx context.Context, - ownerUserID string, - pageNumber, showNumber int32, -) (blacks []*relation.BlackModel, total int64, err error) { - return b.black.FindOwnerBlacks(ctx, ownerUserID, pageNumber, showNumber) +func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, blacks []*relation.BlackModel, err error) { + return b.black.FindOwnerBlacks(ctx, ownerUserID, pagination) } // CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true). diff --git a/pkg/common/db/controller/chatlog.go b/pkg/common/db/controller/chatlog.go deleted file mode 100644 index def490265..000000000 --- a/pkg/common/db/controller/chatlog.go +++ /dev/null @@ -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) -} diff --git a/pkg/common/db/controller/conversation.go b/pkg/common/db/controller/conversation.go index 6f7b8acb1..2a0cb63e4 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -16,9 +16,10 @@ package controller import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" + "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/OpenIMSDK/protocol/constant" @@ -237,7 +238,9 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs if err != nil { 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) }) diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index 5d1c2617f..29b2ef9b1 100644 --- a/pkg/common/db/controller/friend.go +++ b/pkg/common/db/controller/friend.go @@ -18,7 +18,7 @@ import ( "context" "time" - "gorm.io/gorm" + "github.com/OpenIMSDK/tools/pagination" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/errs" @@ -47,35 +47,15 @@ type FriendDatabase interface { // 更新好友备注 UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) // 获取ownerUserID的好友列表 - PageOwnerFriends( - ctx context.Context, - ownerUserID string, - pageNumber, showNumber int32, - ) (friends []*relation.FriendModel, total int64, err error) + PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) // friendUserID在哪些人的好友列表中 - PageInWhoseFriends( - ctx context.Context, - friendUserID string, - pageNumber, showNumber int32, - ) (friends []*relation.FriendModel, total int64, err error) + PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) // 获取我发出去的好友申请 - PageFriendRequestFromMe( - ctx context.Context, - userID string, - pageNumber, showNumber int32, - ) (friends []*relation.FriendRequestModel, total int64, err error) + PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) // 获取我收到的的好友申请 - PageFriendRequestToMe( - ctx context.Context, - userID string, - pageNumber, showNumber int32, - ) (friends []*relation.FriendRequestModel, total int64, err error) + PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) // 获取某人指定好友的信息 - FindFriendsWithError( - ctx context.Context, - ownerUserID string, - friendUserIDs []string, - ) (friends []*relation.FriendModel, err error) + FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*relation.FriendRequestModel, err error) } @@ -83,24 +63,16 @@ type FriendDatabase interface { type friendDatabase struct { friend relation.FriendModelInterface friendRequest relation.FriendRequestModelInterface - tx tx.Tx + tx tx.CtxTx cache cache.FriendCache } -func NewFriendDatabase( - friend relation.FriendModelInterface, - friendRequest relation.FriendRequestModelInterface, - cache cache.FriendCache, - tx tx.Tx, -) FriendDatabase { +func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.CtxTx) FriendDatabase { return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx} } // ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true). -func (f *friendDatabase) CheckIn( - ctx context.Context, - userID1, userID2 string, -) (inUser1Friends bool, inUser2Friends bool, err error) { +func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) { userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1) if err != nil { return @@ -113,50 +85,35 @@ func (f *friendDatabase) CheckIn( } // 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增. -func (f *friendDatabase) AddFriendRequest( - ctx context.Context, - fromUserID, toUserID string, - reqMsg string, - ex string, -) (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 { +func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) { + return f.tx.Transaction(ctx, func(ctx context.Context) error { + _, err := f.friendRequest.Take(ctx, fromUserID, toUserID) + switch { + case err == nil: m := make(map[string]any, 1) m["handle_result"] = 0 m["handle_msg"] = "" m["req_msg"] = reqMsg m["ex"] = ex m["create_time"] = time.Now() - if err := f.friendRequest.NewTx(tx).UpdateByMap(ctx, fromUserID, toUserID, m); err != nil { - return err - } - return nil - } - // 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 { + return f.friendRequest.UpdateByMap(ctx, fromUserID, toUserID, m) + case relation.IsNotFound(err): + return f.friendRequest.Create( + ctx, + []*relation.FriendRequestModel{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}}, + ) + default: return err } - return nil }) } // (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可. -func (f *friendDatabase) BecomeFriends( - ctx context.Context, - ownerUserID string, - friendUserIDs []string, - addSource int32, -) (err error) { - cache := f.cache.NewCache() - if err := f.tx.Transaction(func(tx any) error { +func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) { + return f.tx.Transaction(ctx, func(ctx context.Context) error { + cache := f.cache.NewCache() // 先find 找出重复的 去掉重复的 - fs1, err := f.friend.NewTx(tx).FindFriends(ctx, ownerUserID, friendUserIDs) + fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return err } @@ -168,11 +125,11 @@ func (f *friendDatabase) BecomeFriends( return e.FriendUserID }) - err = f.friend.NewTx(tx).Create(ctx, fs11) + err = f.friend.Create(ctx, fs11) if err != nil { return err } - fs2, err := f.friend.NewTx(tx).FindReversalFriends(ctx, ownerUserID, friendUserIDs) + fs2, err := f.friend.FindReversalFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return err } @@ -184,24 +141,19 @@ func (f *friendDatabase) BecomeFriends( fs22 := utils.DistinctAny(fs2, func(e *relation.FriendModel) string { return e.OwnerUserID }) - err = f.friend.NewTx(tx).Create(ctx, fs22) + err = f.friend.Create(ctx, fs22) if err != nil { return err } newFriendIDs = append(newFriendIDs, ownerUserID) cache = cache.DelFriendIDs(newFriendIDs...) - return nil - }); err != nil { - return nil - } - return cache.ExecDel(ctx) + return cache.ExecDel(ctx) + + }) } // 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝. -func (f *friendDatabase) RefuseFriendRequest( - ctx context.Context, - friendRequest *relation.FriendRequestModel, -) (err error) { +func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID) if err != nil { return err @@ -220,14 +172,11 @@ func (f *friendDatabase) RefuseFriendRequest( } // AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略). -func (f *friendDatabase) AgreeFriendRequest( - ctx context.Context, - friendRequest *relation.FriendRequestModel, -) (err error) { - return f.tx.Transaction(func(tx any) error { +func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) { + return f.tx.Transaction(ctx, func(ctx context.Context) error { defer log.ZDebug(ctx, "return line") 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 { return err } @@ -237,25 +186,25 @@ func (f *friendDatabase) AgreeFriendRequest( friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx) friendRequest.HandleResult = constant.FriendResponseAgree friendRequest.HandleTime = now - err = f.friendRequest.NewTx(tx).Update(ctx, friendRequest) + err = f.friendRequest.Update(ctx, friendRequest) if err != nil { 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 { fr2.HandlerUserID = mcontext.GetOpUserID(ctx) fr2.HandleResult = constant.FriendResponseAgree fr2.HandleTime = now - err = f.friendRequest.NewTx(tx).Update(ctx, fr2) + err = f.friendRequest.Update(ctx, fr2) if err != nil { return err } - } else if err != nil && errs.Unwrap(err) != gorm.ErrRecordNotFound { + } else if err != nil && (!relation.IsNotFound(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 { return err } @@ -286,7 +235,7 @@ func (f *friendDatabase) AgreeFriendRequest( ) } 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 } } @@ -311,47 +260,27 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs } // 获取ownerUserID的好友列表 无结果不返回错误. -func (f *friendDatabase) PageOwnerFriends( - ctx context.Context, - ownerUserID string, - pageNumber, showNumber int32, -) (friends []*relation.FriendModel, total int64, err error) { - return f.friend.FindOwnerFriends(ctx, ownerUserID, pageNumber, showNumber) +func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { + return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination) } // friendUserID在哪些人的好友列表中. -func (f *friendDatabase) PageInWhoseFriends( - ctx context.Context, - friendUserID string, - pageNumber, showNumber int32, -) (friends []*relation.FriendModel, total int64, err error) { - return f.friend.FindInWhoseFriends(ctx, friendUserID, pageNumber, showNumber) +func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) { + return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination) } // 获取我发出去的好友申请 无结果不返回错误. -func (f *friendDatabase) PageFriendRequestFromMe( - ctx context.Context, - userID string, - pageNumber, showNumber int32, -) (friends []*relation.FriendRequestModel, total int64, err error) { - return f.friendRequest.FindFromUserID(ctx, userID, pageNumber, showNumber) +func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { + return f.friendRequest.FindFromUserID(ctx, userID, pagination) } // 获取我收到的的好友申请 无结果不返回错误. -func (f *friendDatabase) PageFriendRequestToMe( - ctx context.Context, - userID string, - pageNumber, showNumber int32, -) (friends []*relation.FriendRequestModel, total int64, err error) { - return f.friendRequest.FindToUserID(ctx, userID, pageNumber, showNumber) +func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) { + return f.friendRequest.FindToUserID(ctx, userID, pagination) } // 获取某人指定好友的信息 如果有好友不存在,也返回错误. -func (f *friendDatabase) FindFriendsWithError( - ctx context.Context, - ownerUserID string, - friendUserIDs []string, -) (friends []*relation.FriendModel, err error) { +func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) { friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs) if err != nil { return @@ -362,10 +291,7 @@ func (f *friendDatabase) FindFriendsWithError( return } -func (f *friendDatabase) FindFriendUserIDs( - ctx context.Context, - ownerUserID string, -) (friendUserIDs []string, err error) { +func (f *friendDatabase) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) { return f.cache.GetFriendIDs(ctx, ownerUserID) } diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index 0df0383e8..4147d59c0 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -16,10 +16,11 @@ package controller import ( "context" - "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" + "github.com/OpenIMSDK/tools/pagination" + "github.com/dtm-labs/rockscache" + "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" @@ -74,7 +75,14 @@ type GroupDatabase interface { 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.StrongConsistency = true rcOptions.RandomExpireAdjustment = 0.2 diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index cba0a6bbd..fb0a9c702 100644 --- a/pkg/common/db/controller/msg.go +++ b/pkg/common/db/controller/msg.go @@ -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) { - cancelCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - currentMaxSeq, err := db.cache.GetMaxSeq(cancelCtx, conversationID) + currentMaxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) if err != nil && errs.Unwrap(err) != redis.Nil { log.ZError(ctx, "db.cache.GetMaxSeq", err) return 0, false, err @@ -386,21 +384,19 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum)) log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID) } else { - prommetrics.MsgInsertRedisSuccessCounter.Add(float64(len(msgs))) + prommetrics.MsgInsertRedisSuccessCounter.Inc() } - cancelCtx, cancel = context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - err = db.cache.SetMaxSeq(cancelCtx, conversationID, currentMaxSeq) + err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq) if err != nil { log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID) prommetrics.SeqSetFailedCounter.Inc() } err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap) - if err2 != nil { + if err != nil { log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID) 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) { @@ -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) { userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID) - if err != nil { - log.ZError(ctx, "cache.GetConversationUserMinSeq error", err) - if errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err - } + if err != nil && errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err } minSeq, err := db.cache.GetMinSeq(ctx, conversationID) - if err != nil { - log.ZError(ctx, "cache.GetMinSeq error", err) - if errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err - } + if err != nil && errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err } maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID) - if err != nil { - log.ZError(ctx, "cache.GetMaxSeq error", err) - if errs.Unwrap(err) != redis.Nil { - return 0, 0, nil, err - } - + if err != nil && errs.Unwrap(err) != redis.Nil { + return 0, 0, nil, err } if userMinSeq < minSeq { 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) 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", - len(successMsgs), "failedSeqs", failedSeqs, "conversationID", conversationID) + log.ZInfo( + ctx, + "db.cache.GetMessagesBySeq", + "userID", + userID, + "conversationID", + conversationID, + "seqs", + seqs, + "successMsgs", + len(successMsgs), + "failedSeqs", + failedSeqs, + "conversationID", + conversationID, + ) if len(failedSeqs) > 0 { mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs) if err != nil { + return 0, 0, nil, err } + successMsgs = append(successMsgs, mongoMsgs...) } return minSeq, maxSeq, successMsgs, nil diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go index 27481f78d..fb5b0ccbe 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/db/controller/third.go @@ -16,9 +16,10 @@ package controller import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "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/table/relation" ) @@ -27,10 +28,10 @@ type ThirdDatabase interface { FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error SetAppBadge(ctx context.Context, userID string, value int) error // 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 - SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.Log, error) - GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*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.LogModel, error) } type thirdDatabase struct { @@ -44,17 +45,17 @@ func (t *thirdDatabase) DeleteLogs(ctx context.Context, logID []string, userID s } // 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) } // 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) } // 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) } diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 6299e7e87..ca703b729 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -16,10 +16,12 @@ package controller import ( "context" + "time" + + "github.com/OpenIMSDK/tools/pagination" "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/pagination" - "time" "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} } - func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error { - // Extract user IDs from the given user models. - userIDs := utils.Slice(users, func(e *relation.UserModel) string { - return e.UserID - }) + // Extract user IDs from the given user models. + userIDs := utils.Slice(users, func(e *relation.UserModel) string { + return e.UserID + }) - // Find existing users in the database. - existingUsers, err := u.userDB.Find(ctx, userIDs) - if err != nil { - return err - } + // Find existing users in the database. + existingUsers, err := u.userDB.Find(ctx, userIDs) + if err != nil { + return err + } - // Determine which users are missing from the database. - missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { - return e.UserID - }) + // Determine which users are missing from the database. + missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string { + return e.UserID + }) - // Create records for missing users. - if len(missingUsers) > 0 { - if err := u.userDB.Create(ctx, missingUsers); err != nil { - return err - } - } + // Create records for missing users. + if len(missingUsers) > 0 { + if err := u.userDB.Create(ctx, missingUsers); err != nil { + return err + } + } - return nil + return nil } - // 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) { users, err = u.cache.GetUsersInfo(ctx, userIDs) diff --git a/pkg/common/db/mgo/black.go b/pkg/common/db/mgo/black.go new file mode 100644 index 000000000..6235639aa --- /dev/null +++ b/pkg/common/db/mgo/black.go @@ -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})) +} diff --git a/pkg/common/db/newmgo/conversation.go b/pkg/common/db/mgo/conversation.go similarity index 70% rename from pkg/common/db/newmgo/conversation.go rename to pkg/common/db/mgo/conversation.go index cfa22d08f..72d04ebb3 100644 --- a/pkg/common/db/newmgo/conversation.go +++ b/pkg/common/db/mgo/conversation.go @@ -1,21 +1,32 @@ -package newmgo +package mgo import ( "context" + "time" + "github.com/OpenIMSDK/protocol/constant" - "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" + "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" - "time" + + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { - return &ConversationMgo{ - coll: db.Collection("conversation"), - }, nil + coll := db.Collection("conversation") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + 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 { @@ -23,15 +34,15 @@ type ConversationMgo struct { } 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) { - 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) { - 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 { 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - return mgotool.Aggregate[string](ctx, c.coll, []bson.M{ + return mgoutil.Aggregate[string](ctx, c.coll, []bson.M{ {"$group": bson.M{"_id": "$conversation_id"}}, {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, }) } 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"}}, {"$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) { - 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) { - 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) { //"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, "msg_destruct_time": bson.M{"$ne": 0}, "$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) { - 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}), + ) } diff --git a/pkg/common/db/newmgo/friend.go b/pkg/common/db/mgo/friend.go similarity index 63% rename from pkg/common/db/newmgo/friend.go rename to pkg/common/db/mgo/friend.go index b02cff7c0..aa9cb0301 100644 --- a/pkg/common/db/newmgo/friend.go +++ b/pkg/common/db/mgo/friend.go @@ -1,13 +1,16 @@ -package newmgo +package mgo 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" + "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" ) // 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. func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { - return &FriendMgo{ - coll: db.Collection(relation.FriendModelCollectionName), - }, nil + coll := db.Collection("friend") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + 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. 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. @@ -33,11 +45,7 @@ func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserID "owner_user_id": ownerUserID, "friend_user_id": bson.M{"$in": friendUserIDs}, } - _, err := f.coll.DeleteMany(ctx, filter) - if err != nil { - return err - } - return nil + return mgoutil.DeleteOne(ctx, f.coll, filter) } // 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, "friend_user_id": friendUserID, } - update := bson.M{"$set": args} - err := mgotool.UpdateOne(ctx, f.coll, filter, update, true) - if err != nil { - return err - } - return nil + return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) } // 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. func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error { - args := map[string]interface{}{"remark": remark} - return f.UpdateByMap(ctx, ownerUserID, friendUserID, args) + return f.UpdateByMap(ctx, ownerUserID, friendUserID, map[string]any{"remark": remark}) } // 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, "friend_user_id": friendUserID, } - friend, err := mgotool.FindOne[*relation.FriendModel](ctx, f.coll, filter) - if err != nil { - return nil, err - } - return friend, nil + return mgoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter) } // 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}, }, } - friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) - if err != nil { - return nil, err - } - return friends, nil + return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // 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, "friend_user_id": bson.M{"$in": friendUserIDs}, } - friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) - if err != nil { - return nil, err - } - return friends, nil + return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // 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}, "friend_user_id": friendUserID, } - friends, err := mgotool.Find[*relation.FriendModel](ctx, f.coll, filter) - if err != nil { - return nil, err - } - return friends, nil + return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) } // 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} - count, friends, err := mgotool.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) - if err != nil { - return nil, 0, err - } - return friends, count, nil + return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, 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} - count, friends, err := mgotool.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) - if err != nil { - return nil, 0, err - } - return friends, count, nil + return mgoutil.FindPage[*relation.FriendModel](ctx, f.coll, filter, pagination) } // FindFriendUserIDs retrieves a list of friend user IDs for a given owner. func (f *FriendMgo) FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error) { filter := bson.M{"owner_user_id": ownerUserID} - friends := []*relation.FriendModel{} - 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 + return mgoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1})) } diff --git a/pkg/common/db/mgo/friend_request.go b/pkg/common/db/mgo/friend_request.go new file mode 100644 index 000000000..c1be87ca2 --- /dev/null +++ b/pkg/common/db/mgo/friend_request.go @@ -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) +} diff --git a/pkg/common/db/newmgo/group.go b/pkg/common/db/mgo/group.go similarity index 50% rename from pkg/common/db/newmgo/group.go rename to pkg/common/db/mgo/group.go index ff5807c0d..3553b6b56 100644 --- a/pkg/common/db/newmgo/group.go +++ b/pkg/common/db/mgo/group.go @@ -1,19 +1,30 @@ -package newmgo +package mgo 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" + "time" + + "github.com/OpenIMSDK/tools/mgoutil" + "github.com/OpenIMSDK/tools/pagination" "go.mongodb.org/mongo-driver/bson" "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) { - return &GroupMgo{ - coll: db.Collection("group"), - }, nil + coll := db.Collection("group") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + 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 { @@ -21,7 +32,7 @@ type GroupMgo struct { } 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) { @@ -32,29 +43,63 @@ func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[strin if len(args) == 0 { 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) { - 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) { - 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) { - 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) { 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) { - //TODO implement me - panic("implement me") + pipeline := bson.A{ + 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 } diff --git a/pkg/common/db/newmgo/group_member.go b/pkg/common/db/mgo/group_member.go similarity index 74% rename from pkg/common/db/newmgo/group_member.go rename to pkg/common/db/mgo/group_member.go index dbc774e80..ed09a028b 100644 --- a/pkg/common/db/newmgo/group_member.go +++ b/pkg/common/db/mgo/group_member.go @@ -1,18 +1,31 @@ -package newmgo +package mgo import ( "context" + "github.com/OpenIMSDK/protocol/constant" - "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" + "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 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 { @@ -20,11 +33,11 @@ type GroupMemberMgo struct { } 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) { - 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 { @@ -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) { - 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) { @@ -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) { - 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) { - 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) { - 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) { - 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) { @@ -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) { - 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) { - 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) { @@ -76,7 +89,7 @@ func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID stri "$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 { diff --git a/pkg/common/db/newmgo/group_request.go b/pkg/common/db/mgo/group_request.go similarity index 64% rename from pkg/common/db/newmgo/group_request.go rename to pkg/common/db/mgo/group_request.go index ea367b653..e88a39bf5 100644 --- a/pkg/common/db/newmgo/group_request.go +++ b/pkg/common/db/mgo/group_request.go @@ -1,16 +1,30 @@ -package newmgo +package mgo 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" + + "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 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 { @@ -18,29 +32,29 @@ type GroupRequestMgo struct { } 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) } diff --git a/pkg/common/db/mgo/log.go b/pkg/common/db/mgo/log.go new file mode 100644 index 000000000..aa280fcf2 --- /dev/null +++ b/pkg/common/db/mgo/log.go @@ -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}) +} diff --git a/pkg/common/db/newmgo/object.go b/pkg/common/db/mgo/object.go similarity index 64% rename from pkg/common/db/newmgo/object.go rename to pkg/common/db/mgo/object.go index 32e3daa4f..5976b2d28 100644 --- a/pkg/common/db/newmgo/object.go +++ b/pkg/common/db/mgo/object.go @@ -1,18 +1,28 @@ -package newmgo +package mgo 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/tools/mgoutil" "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 NewS3Mongo(db *mongo.Database) (relation.ObjectInfoModelInterface, error) { - return &S3Mongo{ - coll: db.Collection("s3"), - }, nil + coll := db.Collection("s3") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + 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 { @@ -30,16 +40,16 @@ func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) erro "group": obj.Group, "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) { 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 { - return mgotool.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) + return mgoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) } diff --git a/pkg/common/db/newmgo/user.go b/pkg/common/db/mgo/user.go similarity index 50% rename from pkg/common/db/newmgo/user.go rename to pkg/common/db/mgo/user.go index 6a9975dff..4a53cb3c4 100644 --- a/pkg/common/db/newmgo/user.go +++ b/pkg/common/db/mgo/user.go @@ -1,20 +1,30 @@ -package newmgo +package mgo 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" + "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" - "time" + + "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) func NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { - return &UserMgo{ - coll: db.Collection("user"), - }, nil + coll := db.Collection("user") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + 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 { @@ -22,50 +32,82 @@ type UserMgo struct { } 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) { if len(args) == 0 { 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - //type Temp struct { - // CreateTime time.Time `bson:"create_time"` - // Number int64 `bson:"number"` - //} - //mgotool.Find(ctx, u.coll, bson.M{"create_time": bson.M{"$gte": start, "$lt": end}}, options.Find().SetProjection(bson.M{"create_time": 1})) - panic("implement me") - return nil, nil + pipeline := bson.A{ + 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, 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 } diff --git a/pkg/common/db/newmgo/friend_request.go b/pkg/common/db/newmgo/friend_request.go deleted file mode 100644 index 99f4dff56..000000000 --- a/pkg/common/db/newmgo/friend_request.go +++ /dev/null @@ -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) -} - diff --git a/pkg/common/db/newmgo/log.go b/pkg/common/db/newmgo/log.go deleted file mode 100644 index f42588745..000000000 --- a/pkg/common/db/newmgo/log.go +++ /dev/null @@ -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}) -} diff --git a/pkg/common/db/newmgo/mgotool/tool.go b/pkg/common/db/newmgo/mgotool/tool.go deleted file mode 100644 index c2c05949c..000000000 --- a/pkg/common/db/newmgo/mgotool/tool.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/relation/black_model.go b/pkg/common/db/relation/black_model.go deleted file mode 100644 index 458012d15..000000000 --- a/pkg/common/db/relation/black_model.go +++ /dev/null @@ -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) -} diff --git a/pkg/common/db/relation/chat_log_model.go b/pkg/common/db/relation/chat_log_model.go deleted file mode 100644 index f183a543f..000000000 --- a/pkg/common/db/relation/chat_log_model.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/relation/conversation_model.go b/pkg/common/db/relation/conversation_model.go deleted file mode 100644 index 73cf1a80e..000000000 --- a/pkg/common/db/relation/conversation_model.go +++ /dev/null @@ -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, -// ) -//} diff --git a/pkg/common/db/relation/doc.go b/pkg/common/db/relation/doc.go deleted file mode 100644 index 41135ac97..000000000 --- a/pkg/common/db/relation/doc.go +++ /dev/null @@ -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" diff --git a/pkg/common/db/relation/friend_model.go b/pkg/common/db/relation/friend_model.go deleted file mode 100644 index 50f4451b5..000000000 --- a/pkg/common/db/relation/friend_model.go +++ /dev/null @@ -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, - "", - ) -} diff --git a/pkg/common/db/relation/friend_request_model.go b/pkg/common/db/relation/friend_request_model.go deleted file mode 100644 index e215f8850..000000000 --- a/pkg/common/db/relation/friend_request_model.go +++ /dev/null @@ -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 -// } diff --git a/pkg/common/db/relation/group_member_model.go b/pkg/common/db/relation/group_member_model.go deleted file mode 100644 index 93885760c..000000000 --- a/pkg/common/db/relation/group_member_model.go +++ /dev/null @@ -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, -// "", -// ) -//} diff --git a/pkg/common/db/relation/group_model.go b/pkg/common/db/relation/group_model.go deleted file mode 100644 index 1b07a4072..000000000 --- a/pkg/common/db/relation/group_model.go +++ /dev/null @@ -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, "") -//} diff --git a/pkg/common/db/relation/group_request_model.go b/pkg/common/db/relation/group_request_model.go deleted file mode 100644 index aa601aaba..000000000 --- a/pkg/common/db/relation/group_request_model.go +++ /dev/null @@ -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()) -//} diff --git a/pkg/common/db/relation/log_model.go b/pkg/common/db/relation/log_model.go deleted file mode 100644 index f5d8a9fae..000000000 --- a/pkg/common/db/relation/log_model.go +++ /dev/null @@ -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} -//} diff --git a/pkg/common/db/relation/meta_db.go b/pkg/common/db/relation/meta_db.go deleted file mode 100644 index 6ab980120..000000000 --- a/pkg/common/db/relation/meta_db.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/relation/mysql_init.go b/pkg/common/db/relation/mysql_init.go deleted file mode 100644 index 41399d5ca..000000000 --- a/pkg/common/db/relation/mysql_init.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/relation/mysql_init_test.go b/pkg/common/db/relation/mysql_init_test.go deleted file mode 100644 index c321dfd9f..000000000 --- a/pkg/common/db/relation/mysql_init_test.go +++ /dev/null @@ -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 } diff --git a/pkg/common/db/relation/object_model.go b/pkg/common/db/relation/object_model.go deleted file mode 100644 index 67b59969b..000000000 --- a/pkg/common/db/relation/object_model.go +++ /dev/null @@ -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) -//} diff --git a/pkg/common/db/relation/user_model.go b/pkg/common/db/relation/user_model.go deleted file mode 100644 index 100bfcf13..000000000 --- a/pkg/common/db/relation/user_model.go +++ /dev/null @@ -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 -//} diff --git a/pkg/common/db/s3/kodo/internal.go b/pkg/common/db/s3/kodo/internal.go deleted file mode 100644 index 3a4943e62..000000000 --- a/pkg/common/db/s3/kodo/internal.go +++ /dev/null @@ -1 +0,0 @@ -package kodo diff --git a/pkg/common/db/s3/kodo/kodo.go b/pkg/common/db/s3/kodo/kodo.go deleted file mode 100644 index d73220b3b..000000000 --- a/pkg/common/db/s3/kodo/kodo.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go old mode 100755 new mode 100644 diff --git a/pkg/common/db/table/relation/black.go b/pkg/common/db/table/relation/black.go index 1697eaec6..50499054c 100644 --- a/pkg/common/db/table/relation/black.go +++ b/pkg/common/db/table/relation/black.go @@ -17,33 +17,27 @@ package relation import ( "context" "time" -) -const ( - BlackModelTableName = "blacks" + "github.com/OpenIMSDK/tools/pagination" ) type BlackModel struct { - OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` - BlockUserID string `gorm:"column:block_user_id;primary_key;size:64"` - CreateTime time.Time `gorm:"column:create_time"` - AddSource int32 `gorm:"column:add_source"` - OperatorUserID string `gorm:"column:operator_user_id;size:64"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (BlackModel) TableName() string { - return BlackModelTableName + OwnerUserID string `bson:"owner_user_id"` + BlockUserID string `bson:"block_user_id"` + CreateTime time.Time `bson:"create_time"` + AddSource int32 `bson:"add_source"` + OperatorUserID string `bson:"operator_user_id"` + Ex string `bson:"ex"` } type BlackModelInterface interface { Create(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) - Update(ctx context.Context, blacks []*BlackModel) (err error) + //UpdateByMap(ctx context.Context, ownerUserID, blockUserID string, args map[string]any) (err error) + //Update(ctx context.Context, blacks []*BlackModel) (err error) Find(ctx context.Context, blacks []*BlackModel) (blackList []*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) FindBlackUserIDs(ctx context.Context, ownerUserID string) (blackUserIDs []string, err error) } diff --git a/pkg/common/db/table/relation/chatlog.go b/pkg/common/db/table/relation/chatlog.go deleted file mode 100644 index 810de3db3..000000000 --- a/pkg/common/db/table/relation/chatlog.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/table/relation/conversation.go b/pkg/common/db/table/relation/conversation.go index ffc82f244..e0a5268ca 100644 --- a/pkg/common/db/table/relation/conversation.go +++ b/pkg/common/db/table/relation/conversation.go @@ -16,35 +16,11 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" -) -const ( - conversationModelTableName = "conversations" + "github.com/OpenIMSDK/tools/pagination" ) -//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 { OwnerUserID string `bson:"owner_user_id"` ConversationID string `bson:"conversation_id"` @@ -66,10 +42,6 @@ type ConversationModel struct { LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"` } -func (ConversationModel) TableName() string { - return conversationModelTableName -} - type ConversationModelInterface interface { Create(ctx context.Context, conversations []*ConversationModel) (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) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, 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) GetAllConversationIDsNumber(ctx context.Context) (int64, 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) GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) diff --git a/pkg/common/db/table/relation/doc.go b/pkg/common/db/table/relation/doc.go deleted file mode 100644 index 32185c8c7..000000000 --- a/pkg/common/db/table/relation/doc.go +++ /dev/null @@ -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" diff --git a/pkg/common/db/table/relation/friend.go b/pkg/common/db/table/relation/friend.go index 481b23525..75dbea850 100644 --- a/pkg/common/db/table/relation/friend.go +++ b/pkg/common/db/table/relation/friend.go @@ -18,36 +18,18 @@ import ( "context" "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. type FriendModel struct { - ID primitive.ObjectID `bson:"_id,omitempty"` - OwnerUserID string `bson:"owner_user_id"` - FriendUserID string `bson:"friend_user_id"` - Remark string `bson:"remark"` - CreateTime time.Time `bson:"create_time"` - AddSource int32 `bson:"add_source"` - OperatorUserID string `bson:"operator_user_id"` - Ex string `bson:"ex"` -} - -// CollectionName returns the name of the MongoDB collection. -func (FriendModel) CollectionName() string { - return FriendModelCollectionName + OwnerUserID string `bson:"owner_user_id"` + FriendUserID string `bson:"friend_user_id"` + Remark string `bson:"remark"` + CreateTime time.Time `bson:"create_time"` + AddSource int32 `bson:"add_source"` + OperatorUserID string `bson:"operator_user_id"` + Ex string `bson:"ex"` } // 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) // 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) - // Update modifies multiple friend documents. - // Update(ctx context.Context, friends []*FriendModel) (err error) - // UpdateRemark updates the remark for a specific friend. + // UpdateRemark modify remarks. UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) // Take retrieves a single friend document. Returns an error if not found. 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(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*FriendModel, err error) // 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(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(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) - // NewTx creates a new transaction. - NewTx(tx any) FriendModelInterface } diff --git a/pkg/common/db/table/relation/friend_request.go b/pkg/common/db/table/relation/friend_request.go index 90d4a7b72..8dceb0778 100644 --- a/pkg/common/db/table/relation/friend_request.go +++ b/pkg/common/db/table/relation/friend_request.go @@ -18,26 +18,19 @@ import ( "context" "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/OpenIMSDK/tools/pagination" ) -const FriendRequestModelCollectionName = "friend_requests" - type FriendRequestModel struct { - ID primitive.ObjectID `bson:"_id,omitempty"` - FromUserID string `bson:"from_user_id"` - ToUserID string `bson:"to_user_id"` - HandleResult int32 `bson:"handle_result"` - ReqMsg string `bson:"req_msg"` - CreateTime time.Time `bson:"create_time"` - HandlerUserID string `bson:"handler_user_id"` - HandleMsg string `bson:"handle_msg"` - HandleTime time.Time `bson:"handle_time"` - Ex string `bson:"ex"` -} - -func (FriendRequestModel) CollectionName() string { - return FriendRequestModelCollectionName + FromUserID string `bson:"from_user_id"` + ToUserID string `bson:"to_user_id"` + HandleResult int32 `bson:"handle_result"` + ReqMsg string `bson:"req_msg"` + CreateTime time.Time `bson:"create_time"` + HandlerUserID string `bson:"handler_user_id"` + HandleMsg string `bson:"handle_msg"` + HandleTime time.Time `bson:"handle_time"` + Ex string `bson:"ex"` } type FriendRequestModelInterface interface { @@ -53,11 +46,8 @@ type FriendRequestModelInterface interface { Find(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 - 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 - 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) - NewTx(tx any) FriendRequestModelInterface - // Check if the record exists - Exist(ctx context.Context, userID string) (exist bool, err error) } diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go index f9afc06b0..bb1ddd878 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/db/table/relation/group.go @@ -16,32 +16,11 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" -) -const ( - GroupModelTableName = "groups" + "github.com/OpenIMSDK/tools/pagination" ) -//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 { GroupID string `bson:"group_id"` GroupName string `bson:"group_name"` @@ -60,10 +39,6 @@ type GroupModel struct { NotificationUserID string `bson:"notification_user_id"` } -func (GroupModel) TableName() string { - return GroupModelTableName -} - type GroupModelInterface interface { Create(ctx context.Context, groups []*GroupModel) (err error) UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) diff --git a/pkg/common/db/table/relation/group_member.go b/pkg/common/db/table/relation/group_member.go index e35f2dd84..88ab87739 100644 --- a/pkg/common/db/table/relation/group_member.go +++ b/pkg/common/db/table/relation/group_member.go @@ -16,28 +16,11 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" -) -const ( - GroupMemberModelTableName = "group_members" + "github.com/OpenIMSDK/tools/pagination" ) -//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 { GroupID string `bson:"group_id"` UserID string `bson:"user_id"` @@ -52,10 +35,6 @@ type GroupMemberModel struct { Ex string `bson:"ex"` } -func (GroupMemberModel) TableName() string { - return GroupMemberModelTableName -} - type GroupMemberModelInterface interface { //NewTx(tx any) GroupMemberModelInterface Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) diff --git a/pkg/common/db/table/relation/group_request.go b/pkg/common/db/table/relation/group_request.go index 83c0cf5bd..39999d799 100644 --- a/pkg/common/db/table/relation/group_request.go +++ b/pkg/common/db/table/relation/group_request.go @@ -16,28 +16,11 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" -) -const ( - GroupRequestModelTableName = "group_requests" + "github.com/OpenIMSDK/tools/pagination" ) -//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 { UserID string `bson:"user_id"` GroupID string `bson:"group_id"` @@ -52,10 +35,6 @@ type GroupRequestModel struct { Ex string `bson:"ex"` } -func (GroupRequestModel) TableName() string { - return GroupRequestModelTableName -} - type GroupRequestModelInterface interface { Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) Delete(ctx context.Context, groupID string, userID string) (err error) diff --git a/pkg/common/db/table/relation/log.go b/pkg/common/db/table/relation/log.go index 7df735676..f690ff8aa 100644 --- a/pkg/common/db/table/relation/log.go +++ b/pkg/common/db/table/relation/log.go @@ -2,23 +2,12 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" -) -//type Log struct { -// 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)"` -//} + "github.com/OpenIMSDK/tools/pagination" +) -type Log struct { +type LogModel struct { LogID string `bson:"log_id"` Platform string `bson:"platform"` UserID string `bson:"user_id"` @@ -31,8 +20,8 @@ type Log struct { } type LogInterface interface { - Create(ctx context.Context, log []*Log) error - Search(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*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, []*LogModel, 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) } diff --git a/pkg/common/db/table/relation/object.go b/pkg/common/db/table/relation/object.go index 6259f425e..678fddcfd 100644 --- a/pkg/common/db/table/relation/object.go +++ b/pkg/common/db/table/relation/object.go @@ -19,10 +19,6 @@ import ( "time" ) -const ( - ObjectInfoModelTableName = "object" -) - type ObjectModel struct { Name string `bson:"name"` UserID string `bson:"user_id"` @@ -35,22 +31,6 @@ type ObjectModel struct { 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 { SetObject(ctx context.Context, obj *ObjectModel) error Take(ctx context.Context, engine string, name string) (*ObjectModel, error) diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go index 11d93b63f..1f26d751f 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/db/table/relation/user.go @@ -16,8 +16,9 @@ package relation import ( "context" - "github.com/openimsdk/open-im-server/v3/pkg/common/pagination" "time" + + "github.com/OpenIMSDK/tools/pagination" ) type UserModel struct { diff --git a/pkg/common/db/table/relation/utils.go b/pkg/common/db/table/relation/utils.go index c944eae8b..380f2410e 100644 --- a/pkg/common/db/table/relation/utils.go +++ b/pkg/common/db/table/relation/utils.go @@ -15,9 +15,8 @@ package relation import ( - "gorm.io/gorm" - "github.com/OpenIMSDK/tools/utils" + "go.mongodb.org/mongo-driver/mongo" ) type BatchUpdateGroupMember struct { @@ -32,5 +31,5 @@ type GroupSimpleUserID struct { } func IsNotFound(err error) bool { - return utils.Unwrap(err) == gorm.ErrRecordNotFound + return utils.Unwrap(err) == mongo.ErrNoDocuments } diff --git a/pkg/common/db/tx/auto.go b/pkg/common/db/tx/auto.go deleted file mode 100644 index bf6817a24..000000000 --- a/pkg/common/db/tx/auto.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/tx/invalid.go b/pkg/common/db/tx/invalid.go deleted file mode 100644 index 193972af5..000000000 --- a/pkg/common/db/tx/invalid.go +++ /dev/null @@ -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) -} diff --git a/pkg/common/db/tx/tx.go b/pkg/common/db/tx/tx.go deleted file mode 100644 index baf9a9a5d..000000000 --- a/pkg/common/db/tx/tx.go +++ /dev/null @@ -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 -} diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go old mode 100755 new mode 100644 diff --git a/pkg/common/db/unrelation/msg.go b/pkg/common/db/unrelation/msg.go old mode 100755 new mode 100644 diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go old mode 100755 new mode 100644