From c0194f6ef447f1a8cf87a520343e204dad9ff920 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Tue, 5 Dec 2023 20:53:02 +0800 Subject: [PATCH] feat: Remove MySQL and implement it all with Mongo (#1508) * fix: GetUserReqApplicationList error when there is a disbanded group chat * fix: error when querying some information about disbanded group * fix: GetUserReqApplicationList dismissed group error * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * fix: the original message referenced by the pull message processing is withdrawn * merge * cicd: robot automated Change * sdkws.MsgData * user * interface{} -> any * user * third * group * group * group * group * group * group * conversation * standalone mysql db model * tx * s3 * group * mongo * group * group * group * group * group * group * refactor: add openim mysql to mongo refactor Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * refactor: add openim mysql to mongo refactor Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * remove mysql * remove mysql * friend * friend * friend * friend * friend * friend * group * convert * index * index * all * all * mysql2mongo * data conversion * up35 * up35 * feat: add format set Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * fix: fix scripts Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> * merge main * merge main * Update init-config.sh * fix: user args check --------- Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> Co-authored-by: withchao Co-authored-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> Co-authored-by: Xinwei Xiong <3293172751@qq.com> --- docker-compose.yml | 123 +-- go.mod | 12 +- go.sum | 4 +- go.work | 1 + internal/api/msg.go | 2 +- internal/msggateway/encoder.go | 8 +- internal/msggateway/n_ws_server.go | 12 +- internal/msgtransfer/init.go | 28 +- .../msgtransfer/online_history_msg_handler.go | 2 +- .../msgtransfer/persistent_msg_handler.go | 119 --- internal/push/offlinepush/getui/body.go | 6 +- internal/push/offlinepush/getui/push.go | 4 +- .../push/offlinepush/jpush/body/audience.go | 2 +- .../push/offlinepush/jpush/body/message.go | 12 +- .../push/offlinepush/jpush/body/platform.go | 2 +- .../push/offlinepush/jpush/body/pushobj.go | 10 +- internal/push/offlinepush/jpush/push.go | 4 +- internal/push/push_to_client.go | 2 +- internal/rpc/conversation/conversaion.go | 33 +- internal/rpc/friend/black.go | 23 +- internal/rpc/friend/friend.go | 108 +-- internal/rpc/group/cache.go | 4 +- internal/rpc/group/db_map.go | 2 +- internal/rpc/group/fill.go | 114 +-- internal/rpc/group/group.go | 900 ++++++++---------- internal/rpc/group/statistics.go | 6 +- internal/rpc/group/super_group.go | 94 +- internal/rpc/msg/utils.go | 7 +- internal/rpc/third/log.go | 24 +- internal/rpc/third/s3.go | 4 +- internal/rpc/third/third.go | 40 +- internal/rpc/user/user.go | 43 +- internal/tools/conversation.go | 10 +- internal/tools/msg.go | 53 +- internal/tools/msg_doc_convert.go | 2 +- pkg/apistruct/manage.go | 2 +- pkg/authverify/token.go | 4 +- pkg/common/cmd/rpc.go | 6 +- pkg/common/config/config.go | 24 +- pkg/common/config/parse.go | 2 +- pkg/common/config/parse_test.go | 2 +- pkg/common/convert/friend.go | 56 +- pkg/common/convert/user.go | 62 +- pkg/common/convert/user_test.go | 87 ++ pkg/common/db/cache/conversation.go | 69 +- pkg/common/db/cache/friend.go | 24 +- pkg/common/db/cache/group.go | 269 +++--- pkg/common/db/cache/meta_cache.go | 7 +- pkg/common/db/cache/msg.go | 69 +- pkg/common/db/cache/msg_test.go | 47 - pkg/common/db/cache/s3.go | 18 +- pkg/common/db/cache/user.go | 42 +- pkg/common/db/controller/black.go | 17 +- pkg/common/db/controller/chatlog.go | 37 - pkg/common/db/controller/conversation.go | 122 ++- pkg/common/db/controller/friend.go | 178 +--- pkg/common/db/controller/group.go | 467 +++------ pkg/common/db/controller/msg.go | 60 +- pkg/common/db/controller/msg_test.go | 2 +- pkg/common/db/controller/s3.go | 5 +- pkg/common/db/controller/third.go | 32 +- pkg/common/db/controller/user.go | 99 +- pkg/common/db/mgo/black.go | 91 ++ pkg/common/db/mgo/conversation.go | 150 +++ pkg/common/db/mgo/friend.go | 131 +++ pkg/common/db/mgo/friend_request.go | 99 ++ pkg/common/db/mgo/group.go | 105 ++ pkg/common/db/mgo/group_member.go | 101 ++ pkg/common/db/mgo/group_request.go | 60 ++ pkg/common/db/mgo/log.go | 70 ++ pkg/common/db/mgo/object.go | 55 ++ pkg/common/db/mgo/user.go | 113 +++ pkg/common/db/relation/black_model.go | 111 --- pkg/common/db/relation/chat_log_model.go | 63 -- pkg/common/db/relation/conversation_model.go | 250 ----- pkg/common/db/relation/doc.go | 15 - pkg/common/db/relation/friend_model.go | 193 ---- .../db/relation/friend_request_model.go | 164 ---- pkg/common/db/relation/group_member_model.go | 197 ---- pkg/common/db/relation/group_model.go | 106 --- pkg/common/db/relation/group_request_model.go | 118 --- pkg/common/db/relation/log_model.go | 49 - pkg/common/db/relation/mysql_init.go | 157 --- pkg/common/db/relation/mysql_init_test.go | 121 --- pkg/common/db/relation/object_model.go | 53 -- pkg/common/db/relation/user_model.go | 136 --- pkg/common/db/s3/cont/controller.go | 4 + pkg/common/db/s3/cos/internal.go | 2 +- pkg/common/db/s3/kodo/internal.go | 1 - pkg/common/db/s3/kodo/kodo.go | 323 ------- pkg/common/db/s3/oss/internal.go | 2 +- pkg/common/db/s3/oss/oss.go | 0 pkg/common/db/table/relation/black.go | 26 +- pkg/common/db/table/relation/conversation.go | 51 +- pkg/common/db/table/relation/friend.go | 69 +- .../db/table/relation/friend_request.go | 55 +- pkg/common/db/table/relation/group.go | 51 +- pkg/common/db/table/relation/group_member.go | 59 +- pkg/common/db/table/relation/group_request.go | 45 +- pkg/common/db/table/relation/log.go | 28 +- pkg/common/db/table/relation/object.go | 29 +- pkg/common/db/table/relation/user.go | 37 +- pkg/common/db/table/relation/utils.go | 5 +- pkg/common/db/table/unrelation/super_group.go | 74 +- pkg/common/db/unrelation/mongo.go | 10 - pkg/common/db/unrelation/msg.go | 0 pkg/common/db/unrelation/msg_convert.go | 2 +- pkg/common/db/unrelation/super_group.go | 293 +++--- pkg/common/db/unrelation/user.go | 0 pkg/common/http/http_client.go | 4 +- pkg/common/http/http_client_test.go | 8 +- pkg/rpcclient/grouphash/grouphash.go | 88 ++ pkg/rpcclient/notification/group.go | 79 +- scripts/install/openim-tools.sh | 1 + test/e2e/api/token/token.go | 2 +- test/e2e/api/user/user.go | 4 +- test/jwt/main.go | 2 +- test/typecheck/typecheck.go | 2 +- tools/component/component.go | 5 +- tools/component/component_test.go | 44 + tools/data-conversion/README.md | 8 +- .../openim/mysql/conversion/conversion.go | 2 +- .../data-conversion/openim/mysql/v3/black.go | 49 + .../openim/mysql/v3}/chatlog.go | 0 .../openim/mysql/v3/conversation.go | 73 ++ .../data-conversion/openim/mysql/v3}/doc.go | 0 .../data-conversion/openim/mysql/v3/friend.go | 78 ++ .../openim/mysql/v3/friend_request.go | 66 ++ .../data-conversion/openim/mysql/v3/group.go | 66 ++ .../openim/mysql/v3/group_member.go | 74 ++ .../openim/mysql/v3/group_request.go | 61 ++ tools/data-conversion/openim/mysql/v3/log.go | 29 + .../data-conversion/openim/mysql/v3/object.go | 45 + tools/data-conversion/openim/mysql/v3/user.go | 72 ++ .../data-conversion/openim/mysql/v3/utils.go | 24 +- .../openim/proto/msg/msg.pb.go | 60 +- .../openim/proto/sdk_ws/ws.pb.go | 8 +- tools/up35/README.md | 67 ++ tools/up35/go.mod | 51 + tools/up35/go.sum | 125 +++ tools/up35/up35.go | 367 +++++++ 141 files changed, 4241 insertions(+), 4826 deletions(-) delete mode 100644 internal/msgtransfer/persistent_msg_handler.go create mode 100644 pkg/common/convert/user_test.go delete mode 100644 pkg/common/db/controller/chatlog.go create mode 100644 pkg/common/db/mgo/black.go create mode 100644 pkg/common/db/mgo/conversation.go create mode 100644 pkg/common/db/mgo/friend.go create mode 100644 pkg/common/db/mgo/friend_request.go create mode 100644 pkg/common/db/mgo/group.go create mode 100644 pkg/common/db/mgo/group_member.go create mode 100644 pkg/common/db/mgo/group_request.go create mode 100644 pkg/common/db/mgo/log.go create mode 100644 pkg/common/db/mgo/object.go create mode 100644 pkg/common/db/mgo/user.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/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 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 create mode 100644 pkg/rpcclient/grouphash/grouphash.go create mode 100644 tools/data-conversion/openim/mysql/v3/black.go rename {pkg/common/db/table/relation => tools/data-conversion/openim/mysql/v3}/chatlog.go (100%) create mode 100644 tools/data-conversion/openim/mysql/v3/conversation.go rename {pkg/common/db/table/relation => tools/data-conversion/openim/mysql/v3}/doc.go (100%) create mode 100644 tools/data-conversion/openim/mysql/v3/friend.go create mode 100644 tools/data-conversion/openim/mysql/v3/friend_request.go create mode 100644 tools/data-conversion/openim/mysql/v3/group.go create mode 100644 tools/data-conversion/openim/mysql/v3/group_member.go create mode 100644 tools/data-conversion/openim/mysql/v3/group_request.go create mode 100644 tools/data-conversion/openim/mysql/v3/log.go create mode 100644 tools/data-conversion/openim/mysql/v3/object.go create mode 100644 tools/data-conversion/openim/mysql/v3/user.go rename pkg/common/db/relation/meta_db.go => tools/data-conversion/openim/mysql/v3/utils.go (70%) create mode 100644 tools/up35/README.md create mode 100644 tools/up35/go.mod create mode 100644 tools/up35/go.sum create mode 100644 tools/up35/up35.go diff --git a/docker-compose.yml b/docker-compose.yml index 1a6626add7..ebf6a3dc45 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,7 @@ services: restart: always networks: server: + # open-im-server_server ipv4_address: ${MYSQL_NETWORK_ADDRESS} mongodb: @@ -142,68 +143,68 @@ services: server: ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS} - openim-admin: - image: ${IMAGE_REGISTRY}/openim-admin-front:v3.4.0 - # image: ghcr.io/openimsdk/openim-admin-front:v3.4.0 - # image: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:v3.4.0 - # image: openim/openim-admin-front:v3.4.0 - container_name: openim-admin - restart: always - ports: - - "${OPENIM_ADMIN_FRONT_PORT}:80" - networks: - server: - ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS} + # openim-admin: + # image: ${IMAGE_REGISTRY}/openim-admin-front:v3.4.0 + # # image: ghcr.io/openimsdk/openim-admin-front:v3.4.0 + # # image: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:v3.4.0 + # # image: openim/openim-admin-front:v3.4.0 + # container_name: openim-admin + # restart: always + # ports: + # - "${OPENIM_ADMIN_FRONT_PORT}:80" + # networks: + # server: + # ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS} - prometheus: - image: prom/prometheus - container_name: prometheus - hostname: prometheus - restart: always - volumes: - - ./config/prometheus.yml:/etc/prometheus/prometheus.yml - - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml - ports: - - "${PROMETHEUS_PORT}:9090" - networks: - server: - ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS} + # prometheus: + # image: prom/prometheus + # container_name: prometheus + # hostname: prometheus + # restart: always + # volumes: + # - ./config/prometheus.yml:/etc/prometheus/prometheus.yml + # - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml + # ports: + # - "${PROMETHEUS_PORT}:9090" + # networks: + # server: + # ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS} - alertmanager: - image: prom/alertmanager - container_name: alertmanager - hostname: alertmanager - restart: always - volumes: - - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml - - ./config/email.tmpl:/etc/alertmanager/email.tmpl - ports: - - "${ALERT_MANAGER_PORT}:9093" - networks: - server: - ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS} + # alertmanager: + # image: prom/alertmanager + # container_name: alertmanager + # hostname: alertmanager + # restart: always + # volumes: + # - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml + # - ./config/email.tmpl:/etc/alertmanager/email.tmpl + # ports: + # - "${ALERT_MANAGER_PORT}:9093" + # networks: + # server: + # ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS} - grafana: - image: grafana/grafana - container_name: grafana - hostname: grafana - user: root - restart: always - ports: - - "${GRAFANA_PORT}:3000" - volumes: - - ${DATA_DIR}/components/grafana:/var/lib/grafana - networks: - server: - ipv4_address: ${GRAFANA_NETWORK_ADDRESS} + # grafana: + # image: grafana/grafana + # container_name: grafana + # hostname: grafana + # user: root + # restart: always + # ports: + # - "${GRAFANA_PORT}:3000" + # volumes: + # - ${DATA_DIR}/components/grafana:/var/lib/grafana + # networks: + # server: + # ipv4_address: ${GRAFANA_NETWORK_ADDRESS} - node-exporter: - image: quay.io/prometheus/node-exporter - container_name: node-exporter - hostname: node-exporter - restart: always - ports: - - "${NODE_EXPORTER_PORT}:9100" - networks: - server: - ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS} + # node-exporter: + # image: quay.io/prometheus/node-exporter + # container_name: node-exporter + # hostname: node-exporter + # restart: always + # ports: + # - "${NODE_EXPORTER_PORT}:9100" + # networks: + # server: + # ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS} diff --git a/go.mod b/go.mod index 8d767dbc1a..bc84bf5860 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,8 @@ require ( github.com/go-playground/validator/v10 v10.15.5 github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/golang/protobuf v1.5.3 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/jinzhu/copier v0.4.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/minio/minio-go/v7 v7.0.63 github.com/mitchellh/mapstructure v1.5.0 @@ -29,8 +27,6 @@ require ( google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.2 - gorm.io/gorm v1.25.5 ) require github.com/google/uuid v1.3.1 @@ -38,10 +34,9 @@ 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 github.com/redis/go-redis/v9 v9.2.1 github.com/tencentyun/cos-go-sdk-v5 v0.7.45 go.uber.org/automaxprocs v1.5.3 @@ -93,6 +88,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect @@ -109,6 +105,7 @@ require ( github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jinzhu/copier v0.3.5 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -152,7 +149,7 @@ require ( golang.org/x/arch v0.3.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect @@ -162,6 +159,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gorm.io/gorm v1.23.8 // indirect ) require ( diff --git a/go.sum b/go.sum index 640b11e89d..063f7691ec 100644 --- a/go.sum +++ b/go.sum @@ -498,8 +498,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc 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/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= diff --git a/go.work b/go.work index 1c819212c8..63100b9f6e 100644 --- a/go.work +++ b/go.work @@ -13,4 +13,5 @@ use ( ./tools/component ./tools/url2im ./tools/data-conversion + ./tools/up35 ) diff --git a/internal/api/msg.go b/internal/api/msg.go index 67b5f1eff2..22182d985c 100644 --- a/internal/api/msg.go +++ b/internal/api/msg.go @@ -150,7 +150,7 @@ func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) { } func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) { - var data interface{} + var data any log.ZDebug(c, "getSendMsgReq", "req", req.Content) switch req.ContentType { case constant.Text: diff --git a/internal/msggateway/encoder.go b/internal/msggateway/encoder.go index 9791acb391..c5f1d00a82 100644 --- a/internal/msggateway/encoder.go +++ b/internal/msggateway/encoder.go @@ -22,8 +22,8 @@ import ( ) type Encoder interface { - Encode(data interface{}) ([]byte, error) - Decode(encodeData []byte, decodeData interface{}) error + Encode(data any) ([]byte, error) + Decode(encodeData []byte, decodeData any) error } type GobEncoder struct{} @@ -32,7 +32,7 @@ func NewGobEncoder() *GobEncoder { return &GobEncoder{} } -func (g *GobEncoder) Encode(data interface{}) ([]byte, error) { +func (g *GobEncoder) Encode(data any) ([]byte, error) { buff := bytes.Buffer{} enc := gob.NewEncoder(&buff) err := enc.Encode(data) @@ -42,7 +42,7 @@ func (g *GobEncoder) Encode(data interface{}) ([]byte, error) { return buff.Bytes(), nil } -func (g *GobEncoder) Decode(encodeData []byte, decodeData interface{}) error { +func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error { buff := bytes.NewBuffer(encodeData) dec := gob.NewDecoder(buff) err := dec.Decode(decodeData) diff --git a/internal/msggateway/n_ws_server.go b/internal/msggateway/n_ws_server.go index 5a061d7e13..737d5db148 100644 --- a/internal/msggateway/n_ws_server.go +++ b/internal/msggateway/n_ws_server.go @@ -49,7 +49,7 @@ type LongConnServer interface { wsHandler(w http.ResponseWriter, r *http.Request) GetUserAllCons(userID string) ([]*Client, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) - Validate(s interface{}) error + Validate(s any) error SetCacheHandler(cache cache.MsgModel) SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry) KickUserConn(client *Client) error @@ -60,6 +60,12 @@ type LongConnServer interface { MessageHandler } +var bufferPool = sync.Pool{ + New: func() any { + return make([]byte, 1024) + }, +} + type WsServer struct { port int wsMaxConnNum int64 @@ -120,7 +126,7 @@ func (ws *WsServer) UnRegister(c *Client) { ws.unregisterChan <- c } -func (ws *WsServer) Validate(s interface{}) error { +func (ws *WsServer) Validate(s any) error { //?question? return nil } @@ -145,7 +151,7 @@ func NewWsServer(opts ...Option) (*WsServer, error) { writeBufferSize: config.writeBufferSize, handshakeTimeout: config.handshakeTimeout, clientPool: sync.Pool{ - New: func() interface{} { + New: func() any { return new(Client) }, }, diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index 8436317eeb..a8d10799f2 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/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go index eb8e500fe1..127cede716 100644 --- a/internal/msgtransfer/online_history_msg_handler.go +++ b/internal/msgtransfer/online_history_msg_handler.go @@ -61,7 +61,7 @@ type TriggerChannelValue struct { type Cmd2Value struct { Cmd int - Value interface{} + Value any } type ContextMsg struct { message *sdkws.MsgData diff --git a/internal/msgtransfer/persistent_msg_handler.go b/internal/msgtransfer/persistent_msg_handler.go deleted file mode 100644 index d105de2fe4..0000000000 --- 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/push/offlinepush/getui/body.go b/internal/push/offlinepush/getui/body.go index 218ed67b4c..01eb22e733 100644 --- a/internal/push/offlinepush/getui/body.go +++ b/internal/push/offlinepush/getui/body.go @@ -21,9 +21,9 @@ import ( ) type Resp struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data interface{} `json:"data"` + Code int `json:"code"` + Msg string `json:"msg"` + Data any `json:"data"` } func (r *Resp) parseError() (err error) { diff --git a/internal/push/offlinepush/getui/push.go b/internal/push/offlinepush/getui/push.go index 1fd65647d5..b657c9c23c 100644 --- a/internal/push/offlinepush/getui/push.go +++ b/internal/push/offlinepush/getui/push.go @@ -159,7 +159,7 @@ func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq P return g.request(ctx, pushURL, pushReq, token, nil) } -func (g *Client) request(ctx context.Context, url string, input interface{}, token string, output interface{}) error { +func (g *Client) request(ctx context.Context, url string, input any, token string, output any) error { header := map[string]string{"token": token} resp := &Resp{} resp.Data = output @@ -170,7 +170,7 @@ func (g *Client) postReturn( ctx context.Context, url string, header map[string]string, - input interface{}, + input any, output RespI, timeout int, ) error { diff --git a/internal/push/offlinepush/jpush/body/audience.go b/internal/push/offlinepush/jpush/body/audience.go index f299308869..43a7148b84 100644 --- a/internal/push/offlinepush/jpush/body/audience.go +++ b/internal/push/offlinepush/jpush/body/audience.go @@ -23,7 +23,7 @@ const ( ) type Audience struct { - Object interface{} + Object any audience map[string][]string } diff --git a/internal/push/offlinepush/jpush/body/message.go b/internal/push/offlinepush/jpush/body/message.go index 670cd4c78c..e885d1d695 100644 --- a/internal/push/offlinepush/jpush/body/message.go +++ b/internal/push/offlinepush/jpush/body/message.go @@ -15,10 +15,10 @@ package body type Message struct { - MsgContent string `json:"msg_content"` - Title string `json:"title,omitempty"` - ContentType string `json:"content_type,omitempty"` - Extras map[string]interface{} `json:"extras,omitempty"` + MsgContent string `json:"msg_content"` + Title string `json:"title,omitempty"` + ContentType string `json:"content_type,omitempty"` + Extras map[string]any `json:"extras,omitempty"` } func (m *Message) SetMsgContent(c string) { @@ -33,9 +33,9 @@ func (m *Message) SetContentType(c string) { m.ContentType = c } -func (m *Message) SetExtras(key string, value interface{}) { +func (m *Message) SetExtras(key string, value any) { if m.Extras == nil { - m.Extras = make(map[string]interface{}) + m.Extras = make(map[string]any) } m.Extras[key] = value } diff --git a/internal/push/offlinepush/jpush/body/platform.go b/internal/push/offlinepush/jpush/body/platform.go index 9de2b87113..1ef136f2c5 100644 --- a/internal/push/offlinepush/jpush/body/platform.go +++ b/internal/push/offlinepush/jpush/body/platform.go @@ -29,7 +29,7 @@ const ( ) type Platform struct { - Os interface{} + Os any osArry []string } diff --git a/internal/push/offlinepush/jpush/body/pushobj.go b/internal/push/offlinepush/jpush/body/pushobj.go index c8c112f69f..3dc133d0a1 100644 --- a/internal/push/offlinepush/jpush/body/pushobj.go +++ b/internal/push/offlinepush/jpush/body/pushobj.go @@ -15,11 +15,11 @@ package body type PushObj struct { - Platform interface{} `json:"platform"` - Audience interface{} `json:"audience"` - Notification interface{} `json:"notification,omitempty"` - Message interface{} `json:"message,omitempty"` - Options interface{} `json:"options,omitempty"` + Platform any `json:"platform"` + Audience any `json:"audience"` + Notification any `json:"notification,omitempty"` + Message any `json:"message,omitempty"` + Options any `json:"options,omitempty"` } func (p *PushObj) SetPlatform(pf *Platform) { diff --git a/internal/push/offlinepush/jpush/push.go b/internal/push/offlinepush/jpush/push.go index 44de7ff655..567269f3c6 100644 --- a/internal/push/offlinepush/jpush/push.go +++ b/internal/push/offlinepush/jpush/push.go @@ -69,11 +69,11 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin pushObj.SetNotification(&no) pushObj.SetMessage(&msg) pushObj.SetOptions(&opt) - var resp interface{} + var resp any return j.request(ctx, pushObj, resp, 5) } -func (j *JPush) request(ctx context.Context, po body.PushObj, resp interface{}, timeout int) error { +func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error { return http2.PostReturn( ctx, config.Config.Push.Jpns.PushUrl, diff --git a/internal/push/push_to_client.go b/internal/push/push_to_client.go index 75a1c13806..2ee8c457fe 100644 --- a/internal/push/push_to_client.go +++ b/internal/push/push_to_client.go @@ -133,7 +133,7 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg return nil } -func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t interface{}) error { +func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t any) error { var notification sdkws.NotificationElem if err := json.Unmarshal(bytes, ¬ification); err != nil { return err diff --git a/internal/rpc/conversation/conversaion.go b/internal/rpc/conversation/conversaion.go index d39881b350..88c9ff7ffe 100644 --- a/internal/rpc/conversation/conversaion.go +++ b/internal/rpc/conversation/conversaion.go @@ -16,6 +16,12 @@ package conversation import ( "context" + "errors" + + "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" @@ -24,13 +30,11 @@ import ( "github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "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" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" @@ -43,24 +47,24 @@ type conversationServer struct { } func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { - db, err := relation.NewGormDB() + rdb, err := cache.NewRedis() if err != nil { return err } - if err := db.AutoMigrate(&tablerelation.ConversationModel{}); err != nil { + mongo, err := unrelation.NewMongo() + if err != nil { return err } - rdb, err := cache.NewRedis() + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) if err != nil { return err } - conversationDB := relation.NewConversationGorm(db) groupRpcClient := rpcclient.NewGroupRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) pbconversation.RegisterConversationServer(server, &conversationServer{ conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), groupRpcClient: &groupRpcClient, - conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewGorm(db)), + conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())), }) return nil } @@ -145,7 +149,7 @@ func (c *conversationServer) SetConversations(ctx context.Context, conversation.ConversationType = req.Conversation.ConversationType conversation.UserID = req.Conversation.UserID conversation.GroupID = req.Conversation.GroupID - m := make(map[string]interface{}) + m := make(map[string]any) if req.Conversation.RecvMsgOpt != nil { m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value if req.Conversation.RecvMsgOpt.Value != conv.RecvMsgOpt { @@ -229,11 +233,12 @@ func (c *conversationServer) SetConversations(ctx context.Context, // 获取超级大群开启免打扰的用户ID. func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) { - userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) - if err != nil { - return nil, err - } - return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil + //userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) + //if err != nil { + // return nil, err + //} + //return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil + return nil, errors.New("deprecated") } // create conversation without notification for msg redis transfer. @@ -284,7 +289,7 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) { if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID, - map[string]interface{}{"max_seq": req.MaxSeq}); err != nil { + map[string]any{"max_seq": req.MaxSeq}); err != nil { return nil, err } return &pbconversation.SetConversationMaxSeqResp{}, nil diff --git a/internal/rpc/friend/black.go b/internal/rpc/friend/black.go index fee2d54809..54cdbb2cce 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 6e6b6d377c..7f22c9d0d1 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,13 +34,13 @@ 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/relation" + "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" ) @@ -52,49 +54,65 @@ type friendServer struct { } func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { - db, err := relation.NewGormDB() + // Initialize MongoDB + mongo, err := unrelation.NewMongo() if err != nil { return err } - if err := db.AutoMigrate(&tablerelation.FriendModel{}, &tablerelation.FriendRequestModel{}, &tablerelation.BlackModel{}); err != nil { + + // Initialize Redis + rdb, err := cache.NewRedis() + if err != nil { return err } - rdb, err := cache.NewRedis() + + friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase()) if err != nil { return err } - blackDB := relation.NewBlackGorm(db) - friendDB := relation.NewFriendGorm(db) + + friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase()) + if err != nil { + return err + } + + blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase()) + if err != nil { + return err + } + + // Initialize RPC clients userRpcClient := rpcclient.NewUserRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) + + // Initialize notification sender notificationSender := notification.NewFriendNotificationSender( &msgRpcClient, notification.WithRpcFunc(userRpcClient.GetUsersInfo), ) + // Register Friend server with refactored MongoDB and Redis integrations pbfriend.RegisterFriendServer(server, &friendServer{ friendDatabase: controller.NewFriendDatabase( - friendDB, - relation.NewFriendRequestGorm(db), - cache.NewFriendCacheRedis(rdb, friendDB, cache.GetDefaultOpt()), - tx.NewGorm(db), + friendMongoDB, + friendRequestMongoDB, + cache.NewFriendCacheRedis(rdb, friendMongoDB, cache.GetDefaultOpt()), + tx.NewMongo(mongo.GetClient()), ), blackDatabase: controller.NewBlackDatabase( - blackDB, - cache.NewBlackCacheRedis(rdb, blackDB, cache.GetDefaultOpt()), + blackMongoDB, + cache.NewBlackCacheRedis(rdb, blackMongoDB, cache.GetDefaultOpt()), ), userRpcClient: &userRpcClient, notificationSender: notificationSender, RegisterCenter: client, conversationRpcClient: rpcclient.NewConversationRpcClient(client), }) + return nil } // ok. -func (s *friendServer) ApplyToAddFriend( - ctx context.Context, - req *pbfriend.ApplyToAddFriendReq, -) (resp *pbfriend.ApplyToAddFriendResp, err error) { +func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.ApplyToAddFriendResp{} if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { @@ -127,10 +145,7 @@ func (s *friendServer) ApplyToAddFriend( } // ok. -func (s *friendServer) ImportFriends( - ctx context.Context, - req *pbfriend.ImportFriendReq, -) (resp *pbfriend.ImportFriendResp, err error) { +func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") if err := authverify.CheckAdmin(ctx); err != nil { return nil, err @@ -165,10 +180,7 @@ func (s *friendServer) ImportFriends( } // ok. -func (s *friendServer) RespondFriendApply( - ctx context.Context, - req *pbfriend.RespondFriendApplyReq, -) (resp *pbfriend.RespondFriendApplyResp, err error) { +func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.RespondFriendApplyResp{} if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil { @@ -204,10 +216,7 @@ func (s *friendServer) RespondFriendApply( } // ok. -func (s *friendServer) DeleteFriend( - ctx context.Context, - req *pbfriend.DeleteFriendReq, -) (resp *pbfriend.DeleteFriendResp, err error) { +func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.DeleteFriendResp{} if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { @@ -228,10 +237,7 @@ func (s *friendServer) DeleteFriend( } // ok. -func (s *friendServer) SetFriendRemark( - ctx context.Context, - req *pbfriend.SetFriendRemarkReq, -) (resp *pbfriend.SetFriendRemarkResp, err error) { +func (s *friendServer) SetFriendRemark(ctx context.Context, 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 { @@ -256,10 +262,7 @@ func (s *friendServer) SetFriendRemark( } // ok. -func (s *friendServer) GetDesignatedFriends( - ctx context.Context, - req *pbfriend.GetDesignatedFriendsReq, -) (resp *pbfriend.GetDesignatedFriendsResp, err error) { +func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.GetDesignatedFriendsReq) (resp *pbfriend.GetDesignatedFriendsResp, err error) { defer log.ZInfo(ctx, utils.GetFuncName()+" Return") resp = &pbfriend.GetDesignatedFriendsResp{} if utils.Duplicate(req.FriendUserIDs) { @@ -290,15 +293,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 } @@ -312,16 +312,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 } @@ -334,10 +331,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) @@ -347,15 +341,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 } @@ -368,10 +359,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/cache.go b/internal/rpc/group/cache.go index 23c57ff891..fc387736dc 100644 --- a/internal/rpc/group/cache.go +++ b/internal/rpc/group/cache.go @@ -26,7 +26,7 @@ func (s *groupServer) GetGroupInfoCache( ctx context.Context, req *pbgroup.GetGroupInfoCacheReq, ) (resp *pbgroup.GetGroupInfoCacheResp, err error) { - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } @@ -38,7 +38,7 @@ func (s *groupServer) GetGroupMemberCache( ctx context.Context, req *pbgroup.GetGroupMemberCacheReq, ) (resp *pbgroup.GetGroupMemberCacheResp, err error) { - members, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID) + members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID) if err != nil { return nil, err } diff --git a/internal/rpc/group/db_map.go b/internal/rpc/group/db_map.go index f793582f8e..07084873c5 100644 --- a/internal/rpc/group/db_map.go +++ b/internal/rpc/group/db_map.go @@ -27,7 +27,7 @@ import ( func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { m := make(map[string]any) if group.GroupName != "" { - m["name"] = group.GroupName + m["group_name"] = group.GroupName } if group.Notification != "" { m["notification"] = group.Notification diff --git a/internal/rpc/group/fill.go b/internal/rpc/group/fill.go index cb47d9f6ee..ac539de198 100644 --- a/internal/rpc/group/fill.go +++ b/internal/rpc/group/fill.go @@ -17,119 +17,9 @@ package group import ( "context" - "github.com/OpenIMSDK/tools/utils" - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) -func (s *groupServer) FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { - members, err := s.GroupDatabase.FindGroupMember(ctx, groupIDs, userIDs, roleLevels) - if err != nil { - return nil, err - } - emptyUserIDs := make(map[string]struct{}) - for _, member := range members { - if member.Nickname == "" || member.FaceURL == "" { - emptyUserIDs[member.UserID] = struct{}{} - } - } - if len(emptyUserIDs) > 0 { - users, err := s.User.GetPublicUserInfoMap(ctx, utils.Keys(emptyUserIDs), true) - if err != nil { - return nil, err - } - for i, member := range members { - user, ok := users[member.UserID] - if !ok { - continue - } - if member.Nickname == "" { - members[i].Nickname = user.Nickname - } - if member.FaceURL == "" { - members[i].FaceURL = user.FaceURL - } - } - } - return members, nil -} - -func (s *groupServer) TakeGroupMember( - ctx context.Context, - groupID string, - userID string, -) (*relationtb.GroupMemberModel, error) { - member, err := s.GroupDatabase.TakeGroupMember(ctx, groupID, userID) - if err != nil { - return nil, err - } - if member.Nickname == "" || member.FaceURL == "" { - user, err := s.User.GetPublicUserInfo(ctx, userID) - if err != nil { - return nil, err - } - if member.Nickname == "" { - member.Nickname = user.Nickname - } - if member.FaceURL == "" { - member.FaceURL = user.FaceURL - } - } - return member, nil -} - -func (s *groupServer) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { - owner, err := s.GroupDatabase.TakeGroupOwner(ctx, groupID) - if err != nil { - return nil, err - } - if owner.Nickname == "" || owner.FaceURL == "" { - user, err := s.User.GetUserInfo(ctx, owner.UserID) - if err != nil { - return nil, err - } - if owner.Nickname == "" { - owner.Nickname = user.Nickname - } - if owner.FaceURL == "" { - owner.FaceURL = user.FaceURL - } - } - return owner, nil -} - -func (s *groupServer) PageGetGroupMember( - ctx context.Context, - groupID string, - pageNumber, showNumber int32, -) (uint32, []*relationtb.GroupMemberModel, error) { - total, members, err := s.GroupDatabase.PageGetGroupMember(ctx, groupID, pageNumber, showNumber) - if err != nil { - return 0, nil, err - } - emptyUserIDs := make(map[string]struct{}) - for _, member := range members { - if member.Nickname == "" || member.FaceURL == "" { - emptyUserIDs[member.UserID] = struct{}{} - } - } - if len(emptyUserIDs) > 0 { - users, err := s.User.GetPublicUserInfoMap(ctx, utils.Keys(emptyUserIDs), true) - if err != nil { - return 0, nil, err - } - for i, member := range members { - user, ok := users[member.UserID] - if !ok { - continue - } - if member.Nickname == "" { - members[i].Nickname = user.Nickname - } - if member.FaceURL == "" { - members[i].FaceURL = user.FaceURL - } - } - } - return total, members, nil +func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMemberModel) error { + return s.Notification.PopulateGroupMember(ctx, members...) } diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 67cd708175..5992ed0311 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -16,24 +16,24 @@ package group import ( "context" - "crypto/md5" - "encoding/binary" - "encoding/json" "fmt" + "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" - pbconversation "github.com/OpenIMSDK/protocol/conversation" - "github.com/OpenIMSDK/protocol/wrapperspb" - "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/OpenIMSDK/tools/mw/specialerror" @@ -54,24 +54,28 @@ 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() + mongo, err := unrelation.NewMongo() if err != nil { return err } - if err := db.AutoMigrate(&relationtb.GroupModel{}, &relationtb.GroupMemberModel{}, &relationtb.GroupRequestModel{}); err != nil { + rdb, err := cache.NewRedis() + if err != nil { return err } - mongo, err := unrelation.NewMongo() + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) if err != nil { return err } - rdb, err := cache.NewRedis() + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) + if err != nil { + return err + } + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) if err != nil { return err } @@ -79,8 +83,8 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e msgRpcClient := rpcclient.NewMessageRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client) var gs groupServer - database := controller.InitGroupDatabase(db, rdb, mongo.GetDatabase(), gs.groupMemberHashCode) - gs.GroupDatabase = database + 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) { users, err := userRpcClient.GetUsersInfo(ctx, userIDs) @@ -92,24 +96,11 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e gs.conversationRpcClient = conversationRpcClient gs.msgRpcClient = msgRpcClient pbgroup.RegisterGroupServer(server, &gs) - //pbgroup.RegisterGroupServer(server, &groupServer{ - // GroupDatabase: database, - // User: userRpcClient, - // Notification: notification.NewGroupNotificationSender(database, &msgRpcClient, &userRpcClient, func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) { - // users, err := userRpcClient.GetUsersInfo(ctx, userIDs) - // if err != nil { - // return nil, err - // } - // return utils.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil - // }), - // conversationRpcClient: conversationRpcClient, - // msgRpcClient: msgRpcClient, - //}) return nil } type groupServer struct { - GroupDatabase controller.GroupDatabase + db controller.GroupDatabase User rpcclient.UserRpcClient Notification *notification.GroupNotificationSender conversationRpcClient rpcclient.ConversationRpcClient @@ -118,11 +109,13 @@ type groupServer struct { func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgroup.NotificationUserInfoUpdateReq) (*pbgroup.NotificationUserInfoUpdateResp, error) { defer log.ZDebug(ctx, "return") - - members, err := s.GroupDatabase.FindGroupMember(ctx, nil, []string{req.UserID}, nil) + members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } groupIDs := make([]string, 0, len(members)) for _, member := range members { if member.Nickname != "" && member.FaceURL != "" { @@ -136,7 +129,7 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro log.ZError(ctx, "NotificationUserInfoUpdate setGroupMemberInfo notification failed", err, "groupID", groupID) } } - if err := s.GroupDatabase.DeleteGroupMemberHash(ctx, groupIDs); err != nil { + if err := s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { log.ZError(ctx, "NotificationUserInfoUpdate DeleteGroupMemberHash", err, "groupID", groupIDs) } @@ -145,7 +138,7 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro func (s *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error { if !authverify.IsAppManagerUid(ctx) { - groupMember, err := s.GroupDatabase.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx)) + groupMember, err := s.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx)) if err != nil { return err } @@ -175,7 +168,7 @@ func (s *groupServer) IsNotFound(err error) bool { func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { if *groupID != "" { - _, err := s.GroupDatabase.TakeGroup(ctx, *groupID) + _, err := s.db.TakeGroup(ctx, *groupID) if err == nil { return errs.ErrGroupIDExisted.Wrap("group id existed " + *groupID) } else if s.IsNotFound(err) { @@ -189,7 +182,7 @@ func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { bi := big.NewInt(0) bi.SetString(id[0:8], 16) id = bi.String() - _, err := s.GroupDatabase.TakeGroup(ctx, id) + _, err := s.db.TakeGroup(ctx, id) if err == nil { continue } else if s.IsNotFound(err) { @@ -203,12 +196,12 @@ func (s *groupServer) GenGroupID(ctx context.Context, groupID *string) error { } func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupReq) (*pbgroup.CreateGroupResp, error) { + if req.GroupInfo.GroupType != constant.WorkingGroup { + return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group type only supports %d", constant.WorkingGroup)) + } if req.OwnerUserID == "" { return nil, errs.ErrArgs.Wrap("no group owner") } - if req.GroupInfo.GroupType != constant.WorkingGroup { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group type %d not support", req.GroupInfo.GroupType)) - } if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil { return nil, err } @@ -256,28 +249,36 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR if err := joinGroup(req.OwnerUserID, constant.GroupOwner); err != nil { return nil, err } - if req.GroupInfo.GroupType == constant.SuperGroup { - if err := s.GroupDatabase.CreateSuperGroup(ctx, group.GroupID, userIDs); err != nil { + for _, userID := range req.AdminUserIDs { + if err := joinGroup(userID, constant.GroupAdmin); err != nil { return nil, err } - } else { - for _, userID := range req.AdminUserIDs { - if err := joinGroup(userID, constant.GroupAdmin); err != nil { - return nil, err - } - } - for _, userID := range req.MemberUserIDs { - if err := joinGroup(userID, constant.GroupOrdinaryUsers); err != nil { - return nil, err - } + } + for _, userID := range req.MemberUserIDs { + if err := joinGroup(userID, constant.GroupOrdinaryUsers); err != nil { + return nil, err } } - if err := s.GroupDatabase.CreateGroup(ctx, []*relationtb.GroupModel{group}, groupMembers); err != nil { + if err := s.db.CreateGroup(ctx, []*relationtb.GroupModel{group}, groupMembers); err != nil { return nil, err } resp := &pbgroup.CreateGroupResp{GroupInfo: &sdkws.GroupInfo{}} resp.GroupInfo = convert.Db2PbGroupInfo(group, req.OwnerUserID, uint32(len(userIDs))) resp.GroupInfo.MemberCount = uint32(len(userIDs)) + tips := &sdkws.GroupCreatedTips{ + Group: resp.GroupInfo, + OperationTime: group.CreateTime.UnixMilli(), + GroupOwnerUser: s.groupMemberDB2PB(groupMembers[0], userMap[groupMembers[0].UserID].AppMangerLevel), + } + for _, member := range groupMembers { + member.Nickname = userMap[member.UserID].Nickname + tips.MemberList = append(tips.MemberList, s.groupMemberDB2PB(member, userMap[member.UserID].AppMangerLevel)) + if member.UserID == opUserID { + tips.OpUser = s.groupMemberDB2PB(member, userMap[member.UserID].AppMangerLevel) + break + } + } + s.Notification.GroupCreatedNotification(ctx, tips) if req.GroupInfo.GroupType == constant.SuperGroup { go func() { for _, userID := range userIDs { @@ -320,35 +321,32 @@ func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJo if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { return nil, err } - var pageNumber, showNumber int32 - if req.Pagination != nil { - pageNumber = req.Pagination.PageNumber - showNumber = req.Pagination.ShowNumber - } - // total, members, err := s.GroupDatabase.PageGroupMember(ctx, nil, []string{req.FromUserID}, nil, pageNumber, showNumber) - total, members, err := s.GroupDatabase.PageGetJoinGroup(ctx, req.FromUserID, pageNumber, showNumber) + total, members, err := s.db.PageGetJoinGroup(ctx, req.FromUserID, req.Pagination) if err != nil { return nil, err } - resp.Total = total + resp.Total = uint32(total) if len(members) == 0 { return resp, nil } groupIDs := utils.Slice(members, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs) + groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } - groupMemberNum, err := s.GroupDatabase.MapGroupMemberNum(ctx, groupIDs) + groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) + owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) @@ -373,7 +371,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite if utils.Duplicate(req.InvitedUserIDs) { return nil, errs.ErrArgs.Wrap("userID duplicate") } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } @@ -392,14 +390,14 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite var opUserID string if !authverify.IsAppManagerUid(ctx) { opUserID = mcontext.GetOpUserID(ctx) - groupMembers, err := s.FindGroupMember(ctx, []string{req.GroupID}, []string{opUserID}, nil) + var err error + groupMember, err = s.db.TakeGroupMember(ctx, req.GroupID, opUserID) if err != nil { return nil, err } - if len(groupMembers) <= 0 { - return nil, errs.ErrNoPermission.Wrap("not in group") + if err := s.PopulateGroupMember(ctx, groupMember); err != nil { + return nil, err } - groupMember = groupMembers[0] } if err := CallbackBeforeInviteUserToGroup(ctx, req); err != nil { @@ -419,8 +417,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 { + if err := s.db.CreateGroupRequest(ctx, requests); err != nil { return nil, err } for _, request := range requests { @@ -435,75 +432,43 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite } } } - - if group.GroupType == constant.SuperGroup { - if err := s.GroupDatabase.CreateSuperGroupMember(ctx, req.GroupID, req.InvitedUserIDs); err != nil { - return nil, err - } - if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, req.InvitedUserIDs); err != nil { - return nil, err - } - for _, userID := range req.InvitedUserIDs { - s.Notification.SuperGroupNotification(ctx, userID, userID) - } - } else { - opUserID := mcontext.GetOpUserID(ctx) - var groupMembers []*relationtb.GroupMemberModel - for _, userID := range req.InvitedUserIDs { - member := &relationtb.GroupMemberModel{ - GroupID: req.GroupID, - UserID: userID, - RoleLevel: constant.GroupOrdinaryUsers, - OperatorUserID: opUserID, - InviterUserID: opUserID, - JoinSource: constant.JoinByInvitation, - JoinTime: time.Now(), - MuteEndTime: time.UnixMilli(0), - } - if err := CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil { - return nil, err - } - groupMembers = append(groupMembers, member) - } - if err := s.GroupDatabase.CreateGroup(ctx, nil, groupMembers); err != nil { - return nil, err + var groupMembers []*relationtb.GroupMemberModel + for _, userID := range req.InvitedUserIDs { + member := &relationtb.GroupMemberModel{ + GroupID: req.GroupID, + UserID: userID, + RoleLevel: constant.GroupOrdinaryUsers, + OperatorUserID: opUserID, + InviterUserID: opUserID, + JoinSource: constant.JoinByInvitation, + JoinTime: time.Now(), + MuteEndTime: time.UnixMilli(0), } - if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, req.InvitedUserIDs); err != nil { + if err := CallbackBeforeMemberJoinGroup(ctx, member, group.Ex); err != nil { return nil, err } - s.Notification.MemberInvitedNotification(ctx, req.GroupID, req.Reason, req.InvitedUserIDs) + groupMembers = append(groupMembers, member) } + if err := s.db.CreateGroup(ctx, nil, groupMembers); err != nil { + return nil, err + } + if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, req.InvitedUserIDs); err != nil { + return nil, err + } + s.Notification.MemberInvitedNotification(ctx, req.GroupID, req.Reason, req.InvitedUserIDs) return resp, nil } func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGroupAllMemberReq) (*pbgroup.GetGroupAllMemberResp, error) { - resp := &pbgroup.GetGroupAllMemberResp{} - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) - if err != nil { - return nil, err - } - if group.GroupType == constant.SuperGroup { - return nil, errs.ErrArgs.Wrap("unsupported super group") - } - members, err := s.FindGroupMember(ctx, []string{req.GroupID}, nil, nil) + members, err := s.db.FindGroupMemberAll(ctx, req.GroupID) if err != nil { return nil, err } - publicUserInfoMap, err := s.GetPublicUserInfoMap(ctx, utils.Filter(members, func(e *relationtb.GroupMemberModel) (string, bool) { - return e.UserID, e.Nickname == "" || e.FaceURL == "" - }), true) - if err != nil { + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } + resp := &pbgroup.GetGroupAllMemberResp{} resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - if userInfo, ok := publicUserInfoMap[e.UserID]; ok { - if e.Nickname == "" { - e.Nickname = userInfo.Nickname - } - if e.FaceURL == "" { - e.FaceURL = userInfo.FaceURL - } - } return convert.Db2PbGroupMember(e) }) return resp, nil @@ -511,20 +476,21 @@ func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbgroup.GetGro func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbgroup.GetGroupMemberListReq) (*pbgroup.GetGroupMemberListResp, error) { resp := &pbgroup.GetGroupMemberListResp{} - total, members, err := s.PageGetGroupMember(ctx, req.GroupID, req.Pagination.PageNumber, req.Pagination.ShowNumber) - log.ZDebug(ctx, "GetGroupMemberList", "total", total, "members", members, "length", len(members)) + total, members, err := s.db.PageGetGroupMember(ctx, req.GroupID, req.Pagination) if err != nil { return nil, err } - resp.Total = total + if err := s.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } + resp.Total = uint32(total) resp.Members = utils.Batch(convert.Db2PbGroupMember, members) - log.ZDebug(ctx, "GetGroupMemberList", "resp", resp, "length", len(resp.Members)) return resp, nil } func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (*pbgroup.KickGroupMemberResp, error) { resp := &pbgroup.KickGroupMemberResp{} - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } @@ -538,92 +504,85 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou if utils.IsContain(opUserID, req.KickedUserIDs) { return nil, errs.ErrArgs.Wrap("opUserID in KickedUserIDs") } - if group.GroupType == constant.SuperGroup { - if err := s.GroupDatabase.DeleteSuperGroupMember(ctx, req.GroupID, req.KickedUserIDs); err != nil { - return nil, err - } - go func() { - for _, userID := range req.KickedUserIDs { - s.Notification.SuperGroupNotification(ctx, userID, userID) - } - }() - } else { - members, err := s.FindGroupMember(ctx, []string{req.GroupID}, append(req.KickedUserIDs, opUserID), nil) - if err != nil { - return nil, err - } - memberMap := make(map[string]*relationtb.GroupMemberModel) - for i, member := range members { - memberMap[member.UserID] = members[i] + members, err := s.db.FindGroupMembers(ctx, req.GroupID, append(req.KickedUserIDs, opUserID)) + if err != nil { + return nil, err + } + if err := s.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } + memberMap := make(map[string]*relationtb.GroupMemberModel) + for i, member := range members { + memberMap[member.UserID] = members[i] + } + isAppManagerUid := authverify.IsAppManagerUid(ctx) + opMember := memberMap[opUserID] + for _, userID := range req.KickedUserIDs { + member, ok := memberMap[userID] + if !ok { + return nil, errs.ErrUserIDNotFound.Wrap(userID) } - isAppManagerUid := authverify.IsAppManagerUid(ctx) - opMember := memberMap[opUserID] - for _, userID := range req.KickedUserIDs { - member, ok := memberMap[userID] - if !ok { - return nil, errs.ErrUserIDNotFound.Wrap(userID) + if !isAppManagerUid { + if opMember == nil { + return nil, errs.ErrNoPermission.Wrap("opUserID no in group") } - if !isAppManagerUid { - if opMember == nil { - return nil, errs.ErrNoPermission.Wrap("opUserID no in group") - } - switch opMember.RoleLevel { - case constant.GroupOwner: - case constant.GroupAdmin: - if member.RoleLevel == constant.GroupOwner || member.RoleLevel == constant.GroupAdmin { - return nil, errs.ErrNoPermission.Wrap("group admins cannot remove the group owner and other admins") - } - case constant.GroupOrdinaryUsers: - return nil, errs.ErrNoPermission.Wrap("opUserID no permission") - default: - return nil, errs.ErrNoPermission.Wrap("opUserID roleLevel unknown") + switch opMember.RoleLevel { + case constant.GroupOwner: + case constant.GroupAdmin: + if member.RoleLevel == constant.GroupOwner || member.RoleLevel == constant.GroupAdmin { + return nil, errs.ErrNoPermission.Wrap("group admins cannot remove the group owner and other admins") } + case constant.GroupOrdinaryUsers: + return nil, errs.ErrNoPermission.Wrap("opUserID no permission") + default: + return nil, errs.ErrNoPermission.Wrap("opUserID roleLevel unknown") } } - num, err := s.GroupDatabase.FindGroupMemberNum(ctx, req.GroupID) - if err != nil { - return nil, err - } - owner, err := s.FindGroupMember(ctx, []string{req.GroupID}, nil, []int32{constant.GroupOwner}) - if err != nil { - return nil, err - } - if err := s.GroupDatabase.DeleteGroupMember(ctx, group.GroupID, req.KickedUserIDs); err != nil { - return nil, err - } - tips := &sdkws.MemberKickedTips{ - Group: &sdkws.GroupInfo{ - GroupID: group.GroupID, - GroupName: group.GroupName, - Notification: group.Notification, - Introduction: group.Introduction, - FaceURL: group.FaceURL, - // OwnerUserID: owner[0].UserID, - CreateTime: group.CreateTime.UnixMilli(), - MemberCount: num, - Ex: group.Ex, - Status: group.Status, - CreatorUserID: group.CreatorUserID, - GroupType: group.GroupType, - NeedVerification: group.NeedVerification, - LookMemberInfo: group.LookMemberInfo, - ApplyMemberFriend: group.ApplyMemberFriend, - NotificationUpdateTime: group.NotificationUpdateTime.UnixMilli(), - NotificationUserID: group.NotificationUserID, - }, - KickedUserList: []*sdkws.GroupMemberFullInfo{}, - } - if len(owner) > 0 { - tips.Group.OwnerUserID = owner[0].UserID - } - if opMember, ok := memberMap[opUserID]; ok { - tips.OpUser = convert.Db2PbGroupMember(opMember) - } - for _, userID := range req.KickedUserIDs { - tips.KickedUserList = append(tips.KickedUserList, convert.Db2PbGroupMember(memberMap[userID])) - } - s.Notification.MemberKickedNotification(ctx, tips) } + num, err := s.db.FindGroupMemberNum(ctx, req.GroupID) + if err != nil { + return nil, err + } + ownerUserIDs, err := s.db.GetGroupRoleLevelMemberIDs(ctx, req.GroupID, constant.GroupOwner) + if err != nil { + return nil, err + } + var ownerUserID string + if len(ownerUserIDs) > 0 { + ownerUserID = ownerUserIDs[0] + } + if err := s.db.DeleteGroupMember(ctx, group.GroupID, req.KickedUserIDs); err != nil { + return nil, err + } + tips := &sdkws.MemberKickedTips{ + Group: &sdkws.GroupInfo{ + GroupID: group.GroupID, + GroupName: group.GroupName, + Notification: group.Notification, + Introduction: group.Introduction, + FaceURL: group.FaceURL, + OwnerUserID: ownerUserID, + CreateTime: group.CreateTime.UnixMilli(), + MemberCount: num, + Ex: group.Ex, + Status: group.Status, + CreatorUserID: group.CreatorUserID, + GroupType: group.GroupType, + NeedVerification: group.NeedVerification, + LookMemberInfo: group.LookMemberInfo, + ApplyMemberFriend: group.ApplyMemberFriend, + NotificationUpdateTime: group.NotificationUpdateTime.UnixMilli(), + NotificationUserID: group.NotificationUserID, + }, + KickedUserList: []*sdkws.GroupMemberFullInfo{}, + } + if opMember, ok := memberMap[opUserID]; ok { + tips.OpUser = convert.Db2PbGroupMember(opMember) + } + for _, userID := range req.KickedUserIDs { + tips.KickedUserList = append(tips.KickedUserList, convert.Db2PbGroupMember(memberMap[userID])) + } + s.Notification.MemberKickedNotification(ctx, tips) if err := s.deleteMemberAndSetConversationSeq(ctx, req.GroupID, req.KickedUserIDs); err != nil { return nil, err } @@ -642,32 +601,21 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG if req.GroupID == "" { return nil, errs.ErrArgs.Wrap("groupID empty") } - members, err := s.FindGroupMember(ctx, []string{req.GroupID}, req.UserIDs, nil) + members, err := s.db.FindGroupMembers(ctx, req.GroupID, req.UserIDs) if err != nil { return nil, err } - publicUserInfoMap, err := s.GetPublicUserInfoMap(ctx, utils.Filter(members, func(e *relationtb.GroupMemberModel) (string, bool) { - return e.UserID, e.Nickname == "" || e.FaceURL == "" - }), true) - if err != nil { + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - if userInfo, ok := publicUserInfoMap[e.UserID]; ok { - if e.Nickname == "" { - e.Nickname = userInfo.Nickname - } - if e.FaceURL == "" { - e.FaceURL = userInfo.FaceURL - } - } return convert.Db2PbGroupMember(e) }) return resp, nil } func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.GetGroupApplicationListReq) (*pbgroup.GetGroupApplicationListResp, error) { - groupIDs, err := s.GroupDatabase.FindUserManagedGroupID(ctx, req.FromUserID) + groupIDs, err := s.db.FindUserManagedGroupID(ctx, req.FromUserID) if err != nil { return nil, err } @@ -675,11 +623,11 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if len(groupIDs) == 0 { return resp, nil } - total, groupRequests, err := s.GroupDatabase.PageGroupRequest(ctx, groupIDs, req.Pagination.PageNumber, req.Pagination.ShowNumber) + total, groupRequests, err := s.db.PageGroupRequest(ctx, groupIDs, req.Pagination) if err != nil { return nil, err } - resp.Total = total + resp.Total = uint32(total) if len(groupRequests) == 0 { return resp, nil } @@ -693,7 +641,7 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if err != nil { return nil, err } - groups, err := s.GroupDatabase.FindGroup(ctx, utils.Distinct(groupIDs)) + groups, err := s.db.FindGroup(ctx, utils.Distinct(groupIDs)) if err != nil { return nil, err } @@ -703,14 +651,17 @@ func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup. if ids := utils.Single(utils.Keys(groupMap), groupIDs); len(ids) > 0 { return nil, errs.ErrGroupIDNotFound.Wrap(strings.Join(ids, ",")) } - groupMemberNumMap, err := s.GroupDatabase.MapGroupMemberNum(ctx, groupIDs) + groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } - owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) + owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, owners...); err != nil { + return nil, err + } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) @@ -729,18 +680,21 @@ func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbgroup.GetGroupsI if len(req.GroupIDs) == 0 { return nil, errs.ErrArgs.Wrap("groupID is empty") } - groups, err := s.GroupDatabase.FindGroup(ctx, req.GroupIDs) + groups, err := s.db.FindGroup(ctx, req.GroupIDs) if err != nil { return nil, err } - groupMemberNumMap, err := s.GroupDatabase.MapGroupMemberNum(ctx, req.GroupIDs) + groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, req.GroupIDs) if err != nil { return nil, err } - owners, err := s.FindGroupMember(ctx, req.GroupIDs, nil, []int32{constant.GroupOwner}) + owners, err := s.db.FindGroupsOwner(ctx, req.GroupIDs) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, owners...); err != nil { + return nil, err + } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) @@ -760,7 +714,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrArgs.Wrap("HandleResult unknown") } if !authverify.IsAppManagerUid(ctx) { - groupMember, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) + groupMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } @@ -768,11 +722,11 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrNoPermission.Wrap("no group owner or admin") } } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } - groupRequest, err := s.GroupDatabase.TakeGroupRequest(ctx, req.GroupID, req.FromUserID) + groupRequest, err := s.db.TakeGroupRequest(ctx, req.GroupID, req.FromUserID) if err != nil { return nil, err } @@ -780,7 +734,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed") } var inGroup bool - if _, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { + if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { inGroup = true // 已经在群里了 } else if !s.IsNotFound(err) { return nil, err @@ -808,7 +762,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup } } log.ZDebug(ctx, "GroupApplicationResponse", "inGroup", inGroup, "HandleResult", req.HandleResult, "member", member) - if err := s.GroupDatabase.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil { + if err := s.db.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil { return nil, err } switch req.HandleResult { @@ -835,7 +789,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err != nil { return nil, err } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } @@ -853,7 +807,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err = CallbackApplyJoinGroupBefore(ctx, reqCall); err != nil { return nil, err } - _, err = s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) + _, err = s.db.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) if err == nil { return nil, errs.ErrArgs.Wrap("already in group") } else if !s.IsNotFound(err) && utils.Unwrap(err) != errs.ErrRecordNotFound { @@ -862,9 +816,6 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) log.ZInfo(ctx, "JoinGroup.groupInfo", "group", group, "eq", group.NeedVerification == constant.Directly) resp = &pbgroup.JoinGroupResp{} if group.NeedVerification == constant.Directly { - if group.GroupType == constant.SuperGroup { - return nil, errs.ErrGroupTypeNotSupport.Wrap() - } groupMember := &relationtb.GroupMemberModel{ GroupID: group.GroupID, UserID: user.UserID, @@ -877,7 +828,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) if err := CallbackBeforeMemberJoinGroup(ctx, groupMember, group.Ex); err != nil { return nil, err } - if err := s.GroupDatabase.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { + if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { return nil, err } @@ -898,7 +849,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) ReqTime: time.Now(), HandledTime: time.Unix(0, 0), } - if err := s.GroupDatabase.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { + if err := s.db.CreateGroupRequest(ctx, []*relationtb.GroupRequestModel{&groupRequest}); err != nil { return nil, err } s.Notification.JoinGroupApplicationNotification(ctx, req) @@ -914,29 +865,21 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) return nil, err } } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + member, err := s.db.TakeGroupMember(ctx, req.GroupID, req.UserID) if err != nil { return nil, err } - if group.GroupType == constant.SuperGroup { - if err := s.GroupDatabase.DeleteSuperGroupMember(ctx, req.GroupID, []string{req.UserID}); err != nil { - return nil, err - } - _ = s.Notification.SuperGroupNotification(ctx, req.UserID, req.UserID) - } else { - info, err := s.TakeGroupMember(ctx, req.GroupID, req.UserID) - if err != nil { - return nil, err - } - if info.RoleLevel == constant.GroupOwner { - return nil, errs.ErrNoPermission.Wrap("group owner can't quit") - } - err = s.GroupDatabase.DeleteGroupMember(ctx, req.GroupID, []string{req.UserID}) - if err != nil { - return nil, err - } - _ = s.Notification.MemberQuitNotification(ctx, s.groupMemberDB2PB(info, 0)) + if member.RoleLevel == constant.GroupOwner { + return nil, errs.ErrNoPermission.Wrap("group owner can't quit") } + if err := s.PopulateGroupMember(ctx, member); err != nil { + return nil, err + } + err = s.db.DeleteGroupMember(ctx, req.GroupID, []string{req.UserID}) + if err != nil { + return nil, err + } + _ = s.Notification.MemberQuitNotification(ctx, s.groupMemberDB2PB(member, 0)) if err := s.deleteMemberAndSetConversationSeq(ctx, req.GroupID, []string{req.UserID}); err != nil { return nil, err } @@ -961,18 +904,21 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf var opMember *relationtb.GroupMemberModel if !authverify.IsAppManagerUid(ctx) { var err error - opMember, err = s.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) + opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } if !(opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin) { return nil, errs.ErrNoPermission.Wrap("no group owner or admin") } + if err := s.PopulateGroupMember(ctx, opMember); err != nil { + return nil, err + } } if err := CallbackBeforeSetGroupInfo(ctx, req); err != nil { return nil, err } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupInfoForSet.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) if err != nil { return nil, err } @@ -980,22 +926,25 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf return nil, utils.Wrap(errs.ErrDismissedAlready, "") } resp := &pbgroup.SetGroupInfoResp{} - count, err := s.GroupDatabase.FindGroupMemberNum(ctx, group.GroupID) + count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) if err != nil { return nil, err } - owner, err := s.TakeGroupOwner(ctx, group.GroupID) + owner, err := s.db.TakeGroupOwner(ctx, group.GroupID) if err != nil { return nil, err } - data := UpdateGroupInfoMap(ctx, req.GroupInfoForSet) - if len(data) == 0 { + if err := s.PopulateGroupMember(ctx, owner); err != nil { + return nil, err + } + update := UpdateGroupInfoMap(ctx, req.GroupInfoForSet) + if len(update) == 0 { return resp, nil } - if err := s.GroupDatabase.UpdateGroup(ctx, group.GroupID, data); err != nil { + if err := s.db.UpdateGroup(ctx, group.GroupID, update); err != nil { return nil, err } - group, err = s.GroupDatabase.TakeGroup(ctx, req.GroupInfoForSet.GroupID) + group, err = s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) if err != nil { return nil, err } @@ -1007,38 +956,33 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf if opMember != nil { tips.OpUser = s.groupMemberDB2PB(opMember, 0) } - var num int + num := len(update) if req.GroupInfoForSet.Notification != "" { - go func() { - nctx := mcontext.NewCtx("@@@" + mcontext.GetOperationID(ctx)) + num-- + func() { conversation := &pbconversation.ConversationReq{ ConversationID: msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, req.GroupInfoForSet.GroupID), ConversationType: constant.SuperGroupChatType, GroupID: req.GroupInfoForSet.GroupID, } - resp, err := s.GetGroupMemberUserIDs(nctx, &pbgroup.GetGroupMemberUserIDsReq{GroupID: req.GroupInfoForSet.GroupID}) + resp, err := s.GetGroupMemberUserIDs(ctx, &pbgroup.GetGroupMemberUserIDsReq{GroupID: req.GroupInfoForSet.GroupID}) if err != nil { log.ZWarn(ctx, "GetGroupMemberIDs", err) return } conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification} - if err := s.conversationRpcClient.SetConversations(nctx, resp.UserIDs, conversation); err != nil { + if err := s.conversationRpcClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil { log.ZWarn(ctx, "SetConversations", err, resp.UserIDs, conversation) } }() - num++ - s.Notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}) - } - switch len(data) - num { - case 0: - case 1: - if req.GroupInfoForSet.GroupName == "" { - s.Notification.GroupInfoSetNotification(ctx, tips) - } else { - s.Notification.GroupInfoSetNameNotification(ctx, &sdkws.GroupInfoSetNameTips{Group: tips.Group, OpUser: tips.OpUser}) - } - default: - s.Notification.GroupInfoSetNotification(ctx, tips) + _ = s.Notification.GroupInfoSetAnnouncementNotification(ctx, &sdkws.GroupInfoSetAnnouncementTips{Group: tips.Group, OpUser: tips.OpUser}) + } + if req.GroupInfoForSet.GroupName != "" { + num-- + _ = s.Notification.GroupInfoSetNameNotification(ctx, &sdkws.GroupInfoSetNameTips{Group: tips.Group, OpUser: tips.OpUser}) + } + if num > 0 { + _ = s.Notification.GroupInfoSetNotification(ctx, tips) } if err := CallbackAfterSetGroupInfo(ctx, req); err != nil { return nil, err @@ -1048,7 +992,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (*pbgroup.TransferGroupOwnerResp, error) { resp := &pbgroup.TransferGroupOwnerResp{} - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } @@ -1058,10 +1002,13 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans if req.OldOwnerUserID == req.NewOwnerUserID { return nil, errs.ErrArgs.Wrap("OldOwnerUserID == NewOwnerUserID") } - members, err := s.FindGroupMember(ctx, []string{req.GroupID}, []string{req.OldOwnerUserID, req.NewOwnerUserID}, nil) + members, err := s.db.FindGroupMembers(ctx, req.GroupID, []string{req.OldOwnerUserID, req.NewOwnerUserID}) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } memberMap := utils.SliceToMap(members, func(e *relationtb.GroupMemberModel) string { return e.UserID }) if ids := utils.Single([]string{req.OldOwnerUserID, req.NewOwnerUserID}, utils.Keys(memberMap)); len(ids) > 0 { return nil, errs.ErrArgs.Wrap("user not in group " + strings.Join(ids, ",")) @@ -1079,7 +1026,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans return nil, errs.ErrNoPermission.Wrap("no permission transfer group owner") } } - if err := s.GroupDatabase.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil { + if err := s.db.TransferGroupOwner(ctx, req.GroupID, req.OldOwnerUserID, req.NewOwnerUserID, newOwner.RoleLevel); err != nil { return nil, err } @@ -1097,10 +1044,12 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) err error ) if req.GroupID != "" { - groups, err = s.GroupDatabase.FindGroup(ctx, []string{req.GroupID}) + groups, err = s.db.FindGroup(ctx, []string{req.GroupID}) resp.Total = uint32(len(groups)) } else { - resp.Total, groups, err = s.GroupDatabase.SearchGroup(ctx, req.GroupName, req.Pagination.PageNumber, req.Pagination.ShowNumber) + var total int64 + total, groups, err = s.db.SearchGroup(ctx, req.GroupName, req.Pagination) + resp.Total = uint32(total) } if err != nil { return nil, err @@ -1108,14 +1057,14 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) groupIDs := utils.Slice(groups, func(e *relationtb.GroupModel) string { return e.GroupID }) - ownerMembers, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) + ownerMembers, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } ownerMemberMap := utils.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - groupMemberNumMap, err := s.GroupDatabase.MapGroupMemberNum(ctx, groupIDs) + groupMemberNumMap, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } @@ -1135,26 +1084,15 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq) func (s *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGroupMembersCMSReq) (*pbgroup.GetGroupMembersCMSResp, error) { resp := &pbgroup.GetGroupMembersCMSResp{} - total, members, err := s.GroupDatabase.SearchGroupMember(ctx, req.UserName, []string{req.GroupID}, nil, nil, req.Pagination.PageNumber, req.Pagination.ShowNumber) + total, members, err := s.db.SearchGroupMember(ctx, req.UserName, req.GroupID, req.Pagination) if err != nil { return nil, err } - resp.Total = total - publicUserInfoMap, err := s.GetPublicUserInfoMap(ctx, utils.Filter(members, func(e *relationtb.GroupMemberModel) (string, bool) { - return e.UserID, e.Nickname == "" || e.FaceURL == "" - }), true) - if err != nil { + resp.Total = uint32(total) + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - if userInfo, ok := publicUserInfoMap[e.UserID]; ok { - if e.Nickname == "" { - e.Nickname = userInfo.Nickname - } - if e.FaceURL == "" { - e.FaceURL = userInfo.FaceURL - } - } return convert.Db2PbGroupMember(e) }) return resp, nil @@ -1166,37 +1104,35 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou if err != nil { return nil, err } - var pageNumber, showNumber int32 - if req.Pagination != nil { - pageNumber = req.Pagination.PageNumber - showNumber = req.Pagination.ShowNumber - } - total, requests, err := s.GroupDatabase.PageGroupRequestUser(ctx, req.UserID, pageNumber, showNumber) + total, requests, err := s.db.PageGroupRequestUser(ctx, req.UserID, req.Pagination) if err != nil { return nil, err } - resp.Total = total + resp.Total = uint32(total) if len(requests) == 0 { return resp, nil } groupIDs := utils.Distinct(utils.Slice(requests, func(e *relationtb.GroupRequestModel) string { return e.GroupID })) - groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs) + groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } groupMap := utils.SliceToMap(groups, func(e *relationtb.GroupModel) string { return e.GroupID }) - owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) + owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, owners...); err != nil { + return nil, err + } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - groupMemberNum, err := s.GroupDatabase.MapGroupMemberNum(ctx, groupIDs) + groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } @@ -1213,7 +1149,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgrou func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGroupReq) (*pbgroup.DismissGroupResp, error) { defer log.ZInfo(ctx, "DismissGroup.return") resp := &pbgroup.DismissGroupResp{} - owner, err := s.TakeGroupOwner(ctx, req.GroupID) + owner, err := s.db.TakeGroupOwner(ctx, req.GroupID) if err != nil { return nil, err } @@ -1222,41 +1158,34 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou return nil, errs.ErrNoPermission.Wrap("not group owner") } } - group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) + if err := s.PopulateGroupMember(ctx, owner); err != nil { + return nil, err + } + group, err := s.db.TakeGroup(ctx, req.GroupID) if err != nil { return nil, err } if req.DeleteMember == false && group.Status == constant.GroupStatusDismissed { return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed") } - //if group.Status == constant.GroupStatusDismissed { - // return nil, errs.ErrArgs.Wrap("group status is dismissed") - //} - if err := s.GroupDatabase.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { + if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { return nil, err } - if group.GroupType == constant.SuperGroup { - if err := s.GroupDatabase.DeleteSuperGroup(ctx, group.GroupID); err != nil { + if !req.DeleteMember { + num, err := s.db.FindGroupMemberNum(ctx, req.GroupID) + if err != nil { return nil, err } - } else { - if !req.DeleteMember { - num, err := s.GroupDatabase.FindGroupMemberNum(ctx, req.GroupID) - if err != nil { - return nil, err - } - // s.Notification.GroupDismissedNotification(ctx, req) - tips := &sdkws.GroupDismissedTips{ - Group: s.groupDB2PB(group, owner.UserID, num), - OpUser: &sdkws.GroupMemberFullInfo{}, - } - if mcontext.GetOpUserID(ctx) == owner.UserID { - tips.OpUser = s.groupMemberDB2PB(owner, 0) - } - s.Notification.GroupDismissedNotification(ctx, tips) + tips := &sdkws.GroupDismissedTips{ + Group: s.groupDB2PB(group, owner.UserID, num), + OpUser: &sdkws.GroupMemberFullInfo{}, } + if mcontext.GetOpUserID(ctx) == owner.UserID { + tips.OpUser = s.groupMemberDB2PB(owner, 0) + } + 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 } @@ -1275,15 +1204,15 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGroupMemberReq) (*pbgroup.MuteGroupMemberResp, error) { resp := &pbgroup.MuteGroupMemberResp{} - //if err := tokenverify.CheckAccessV3(ctx, req.UserID); err != nil { - // return nil, err - //} - member, err := s.TakeGroupMember(ctx, req.GroupID, req.UserID) + member, err := s.db.TakeGroupMember(ctx, req.GroupID, req.UserID) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, member); err != nil { + return nil, err + } if !authverify.IsAppManagerUid(ctx) { - opMember, err := s.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) + opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } @@ -1301,7 +1230,7 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou } } data := UpdateGroupMemberMutedTimeMap(time.Now().Add(time.Second * time.Duration(req.MutedSeconds))) - if err := s.GroupDatabase.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { + if err := s.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } s.Notification.GroupMemberMutedNotification(ctx, req.GroupID, req.UserID, req.MutedSeconds) @@ -1309,29 +1238,15 @@ func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbgroup.MuteGrou } func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.CancelMuteGroupMemberReq) (*pbgroup.CancelMuteGroupMemberResp, error) { - resp := &pbgroup.CancelMuteGroupMemberResp{} - //member, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.UserID) - //if err != nil { - // return nil, err - //} - //if !(mcontext.GetOpUserID(ctx) == req.UserID || tokenverify.IsAppManagerUid(ctx)) { - // opMember, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) - // if err != nil { - // return nil, err - // } - // if opMember.RoleLevel <= member.RoleLevel { - // return nil, errs.ErrNoPermission.Wrap(fmt.Sprintf("self RoleLevel %d target %d", opMember.RoleLevel, member.RoleLevel)) - // } - //} - //if err := tokenverify.CheckAccessV3(ctx, req.UserID); err != nil { - // return nil, err - //} - member, err := s.TakeGroupMember(ctx, req.GroupID, req.UserID) + member, err := s.db.TakeGroupMember(ctx, req.GroupID, req.UserID) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, member); err != nil { + return nil, err + } if !authverify.IsAppManagerUid(ctx) { - opMember, err := s.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) + opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) if err != nil { return nil, err } @@ -1349,11 +1264,11 @@ func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbgroup.Ca } } data := UpdateGroupMemberMutedTimeMap(time.Unix(0, 0)) - if err := s.GroupDatabase.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { + if err := s.db.UpdateGroupMember(ctx, member.GroupID, member.UserID, data); err != nil { return nil, err } s.Notification.GroupMemberCancelMutedNotification(ctx, req.GroupID, req.UserID) - return resp, nil + return &pbgroup.CancelMuteGroupMemberResp{}, nil } func (s *groupServer) MuteGroup(ctx context.Context, req *pbgroup.MuteGroupReq) (*pbgroup.MuteGroupResp, error) { @@ -1361,7 +1276,7 @@ func (s *groupServer) MuteGroup(ctx context.Context, req *pbgroup.MuteGroupReq) if err := s.CheckGroupAdmin(ctx, req.GroupID); err != nil { return nil, err } - if err := s.GroupDatabase.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupStatusMuted)); err != nil { + if err := s.db.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupStatusMuted)); err != nil { return nil, err } s.Notification.GroupMutedNotification(ctx, req.GroupID) @@ -1373,7 +1288,7 @@ func (s *groupServer) CancelMuteGroup(ctx context.Context, req *pbgroup.CancelMu if err := s.CheckGroupAdmin(ctx, req.GroupID); err != nil { return nil, err } - if err := s.GroupDatabase.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupOk)); err != nil { + if err := s.db.UpdateGroup(ctx, req.GroupID, UpdateGroupStatusMap(constant.GroupOk)); err != nil { return nil, err } s.Notification.GroupCancelMutedNotification(ctx, req.GroupID) @@ -1385,97 +1300,90 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr if len(req.Members) == 0 { return nil, errs.ErrArgs.Wrap("members empty") } + opUserID := mcontext.GetOpUserID(ctx) + if opUserID == "" { + return nil, errs.ErrNoPermission.Wrap("no op user id") + } + isAppManagerUid := authverify.IsAppManagerUid(ctx) for i := range req.Members { req.Members[i].FaceURL = nil } - duplicateMap := make(map[[2]string]struct{}) - userIDMap := make(map[string]struct{}) - groupIDMap := make(map[string]struct{}) - for _, member := range req.Members { - key := [...]string{member.GroupID, member.UserID} - if _, ok := duplicateMap[key]; ok { - return nil, errs.ErrArgs.Wrap("group user duplicate") + groupMembers := make(map[string][]*pbgroup.SetGroupMemberInfo) + for i, member := range req.Members { + if member.RoleLevel != nil { + switch member.RoleLevel.Value { + case constant.GroupOwner: + return nil, errs.ErrNoPermission.Wrap("cannot set ungroup owner") + case constant.GroupAdmin, constant.GroupOrdinaryUsers: + default: + return nil, errs.ErrArgs.Wrap("invalid role level") + } } - duplicateMap[key] = struct{}{} - userIDMap[member.UserID] = struct{}{} - groupIDMap[member.GroupID] = struct{}{} - } - groupIDs := utils.Keys(groupIDMap) - userIDs := utils.Keys(userIDMap) - members, err := s.FindGroupMember(ctx, groupIDs, append(userIDs, mcontext.GetOpUserID(ctx)), nil) - if err != nil { - return nil, err - } - for _, member := range members { - delete(duplicateMap, [...]string{member.GroupID, member.UserID}) - } - if len(duplicateMap) > 0 { - return nil, errs.ErrArgs.Wrap("user not found" + strings.Join(utils.Slice(utils.Keys(duplicateMap), func(e [2]string) string { - return fmt.Sprintf("[group: %s user: %s]", e[0], e[1]) - }), ",")) + groupMembers[member.GroupID] = append(groupMembers[member.GroupID], req.Members[i]) } - memberMap := utils.SliceToMap(members, func(e *relationtb.GroupMemberModel) [2]string { - return [...]string{e.GroupID, e.UserID} - }) - if !authverify.IsAppManagerUid(ctx) { - opUserID := mcontext.GetOpUserID(ctx) - for _, member := range req.Members { - if member.RoleLevel != nil { - switch member.RoleLevel.Value { - case constant.GroupOrdinaryUsers, constant.GroupAdmin: - default: - return nil, errs.ErrArgs.Wrap("invalid role level") - } - } - opMember, ok := memberMap[[...]string{member.GroupID, opUserID}] - if !ok { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("user %s not in group %s", opUserID, member.GroupID)) + for groupID, members := range groupMembers { + temp := make(map[string]struct{}) + userIDs := make([]string, 0, len(members)+1) + for _, member := range members { + if _, ok := temp[member.UserID]; ok { + return nil, errs.ErrArgs.Wrap(fmt.Sprintf("repeat group %s user %s", member.GroupID, member.UserID)) } + temp[member.UserID] = struct{}{} + userIDs = append(userIDs, member.UserID) + } + if _, ok := temp[opUserID]; !ok { + userIDs = append(userIDs, opUserID) + } + dbMembers, err := s.db.FindGroupMembers(ctx, groupID, userIDs) + if err != nil { + return nil, err + } + opUserIndex := -1 + for i, member := range dbMembers { if member.UserID == opUserID { - if member.RoleLevel != nil { - return nil, errs.ErrNoPermission.Wrap("can not change self role level") - } - continue + opUserIndex = i + break } - if opMember.RoleLevel == constant.GroupOrdinaryUsers { - return nil, errs.ErrNoPermission.Wrap("ordinary users can not change other role level") + } + switch len(userIDs) - len(dbMembers) { + case 0: + if !isAppManagerUid { + roleLevel := dbMembers[opUserIndex].RoleLevel + if roleLevel != constant.GroupOwner { + switch roleLevel { + case constant.GroupAdmin: + for _, member := range dbMembers { + if member.RoleLevel == constant.GroupOwner { + return nil, errs.ErrNoPermission.Wrap("admin can not change group owner") + } + if member.RoleLevel == constant.GroupAdmin && member.UserID != opUserID { + return nil, errs.ErrNoPermission.Wrap("admin can not change other group admin") + } + } + case constant.GroupOrdinaryUsers: + for _, member := range dbMembers { + if !(member.RoleLevel == constant.GroupOrdinaryUsers && member.UserID == opUserID) { + return nil, errs.ErrNoPermission.Wrap("ordinary users can not change other role level") + } + } + default: + for _, member := range dbMembers { + if member.RoleLevel >= roleLevel { + return nil, errs.ErrNoPermission.Wrap("can not change higher role level") + } + } + } + } } - dbMember, ok := memberMap[[...]string{member.GroupID, member.UserID}] - if !ok { - return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("user %s not in group %s", member.UserID, member.GroupID)) + case 1: + if opUserIndex >= 0 { + return nil, errs.ErrArgs.Wrap("user not in group") } - //if opMember.RoleLevel == constant.GroupOwner { - // continue - //} - //if dbMember.RoleLevel == constant.GroupOwner { - // return nil, errs.ErrNoPermission.Wrap("change group owner") - //} - //if opMember.RoleLevel == constant.GroupAdmin && dbMember.RoleLevel == constant.GroupAdmin { - // return nil, errs.ErrNoPermission.Wrap("admin can not change other admin role info") - //} - switch opMember.RoleLevel { - case constant.GroupOrdinaryUsers: - return nil, errs.ErrNoPermission.Wrap("ordinary users can not change other role level") - case constant.GroupAdmin: - if dbMember.RoleLevel != constant.GroupOrdinaryUsers { - return nil, errs.ErrNoPermission.Wrap("admin can not change other role level") - } - if member.RoleLevel != nil { - return nil, errs.ErrNoPermission.Wrap("admin can not change other role level") - } - case constant.GroupOwner: - //if member.RoleLevel != nil && member.RoleLevel.Value == constant.GroupOwner { - // return nil, errs.ErrNoPermission.Wrap("owner only one") - //} + if !isAppManagerUid { + return nil, errs.ErrNoPermission.Wrap("user not in group") } - } - } - for _, member := range req.Members { - if member.RoleLevel == nil { - continue - } - if memberMap[[...]string{member.GroupID, member.UserID}].RoleLevel == constant.GroupOwner { - return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group %s user %s is owner", member.GroupID, member.UserID)) + default: + return nil, errs.ErrArgs.Wrap("user not in group") } } for i := 0; i < len(req.Members); i++ { @@ -1483,7 +1391,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr return nil, err } } - if err = s.GroupDatabase.UpdateGroupMembers(ctx, utils.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *relationtb.BatchUpdateGroupMember { + if err := s.db.UpdateGroupMembers(ctx, utils.Slice(req.Members, func(e *pbgroup.SetGroupMemberInfo) *relationtb.BatchUpdateGroupMember { return &relationtb.BatchUpdateGroupMember{ GroupID: e.GroupID, UserID: e.UserID, @@ -1502,10 +1410,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr } } if member.Nickname != nil || member.FaceURL != nil || member.Ex != nil { - log.ZDebug(ctx, "setGroupMemberInfo notification", "member", member.UserID) - if err := s.Notification.GroupMemberInfoSetNotification(ctx, member.GroupID, member.UserID); err != nil { - log.ZError(ctx, "setGroupMemberInfo notification failed", err, "member", member.UserID, "groupID", member.GroupID) - } + s.Notification.GroupMemberInfoSetNotification(ctx, member.GroupID, member.UserID) } } for i := 0; i < len(req.Members); i++ { @@ -1525,7 +1430,7 @@ func (s *groupServer) GetGroupAbstractInfo(ctx context.Context, req *pbgroup.Get if utils.Duplicate(req.GroupIDs) { return nil, errs.ErrArgs.Wrap("groupIDs duplicate") } - groups, err := s.GroupDatabase.FindGroup(ctx, req.GroupIDs) + groups, err := s.db.FindGroup(ctx, req.GroupIDs) if err != nil { return nil, err } @@ -1534,7 +1439,7 @@ func (s *groupServer) GetGroupAbstractInfo(ctx context.Context, req *pbgroup.Get })); len(ids) > 0 { return nil, errs.ErrGroupIDNotFound.Wrap("not found group " + strings.Join(ids, ",")) } - groupUserMap, err := s.GroupDatabase.MapGroupMemberUserID(ctx, req.GroupIDs) + groupUserMap, err := s.db.MapGroupMemberUserID(ctx, req.GroupIDs) if err != nil { return nil, err } @@ -1553,25 +1458,14 @@ func (s *groupServer) GetUserInGroupMembers(ctx context.Context, req *pbgroup.Ge if len(req.GroupIDs) == 0 { return nil, errs.ErrArgs.Wrap("groupIDs empty") } - members, err := s.FindGroupMember(ctx, []string{req.UserID}, req.GroupIDs, nil) + members, err := s.db.FindGroupMemberUser(ctx, req.GroupIDs, req.UserID) if err != nil { return nil, err } - publicUserInfoMap, err := s.GetPublicUserInfoMap(ctx, utils.Filter(members, func(e *relationtb.GroupMemberModel) (string, bool) { - return e.UserID, e.Nickname == "" || e.FaceURL == "" - }), true) - if err != nil { + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - if userInfo, ok := publicUserInfoMap[e.UserID]; ok { - if e.Nickname == "" { - e.Nickname = userInfo.Nickname - } - if e.FaceURL == "" { - e.FaceURL = userInfo.FaceURL - } - } return convert.Db2PbGroupMember(e) }) return resp, nil @@ -1579,7 +1473,7 @@ func (s *groupServer) GetUserInGroupMembers(ctx context.Context, req *pbgroup.Ge func (s *groupServer) GetGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetGroupMemberUserIDsReq) (resp *pbgroup.GetGroupMemberUserIDsResp, err error) { resp = &pbgroup.GetGroupMemberUserIDsResp{} - resp.UserIDs, err = s.GroupDatabase.FindGroupMemberUserID(ctx, req.GroupID) + resp.UserIDs, err = s.db.FindGroupMemberUserID(ctx, req.GroupID) if err != nil { return nil, err } @@ -1591,25 +1485,14 @@ func (s *groupServer) GetGroupMemberRoleLevel(ctx context.Context, req *pbgroup. if len(req.RoleLevels) == 0 { return nil, errs.ErrArgs.Wrap("RoleLevels empty") } - members, err := s.FindGroupMember(ctx, []string{req.GroupID}, nil, req.RoleLevels) + members, err := s.db.FindGroupMemberRoleLevels(ctx, req.GroupID, req.RoleLevels) if err != nil { return nil, err } - publicUserInfoMap, err := s.GetPublicUserInfoMap(ctx, utils.Filter(members, func(e *relationtb.GroupMemberModel) (string, bool) { - return e.UserID, e.Nickname == "" || e.FaceURL == "" - }), true) - if err != nil { + if err := s.PopulateGroupMember(ctx, members...); err != nil { return nil, err } resp.Members = utils.Slice(members, func(e *relationtb.GroupMemberModel) *sdkws.GroupMemberFullInfo { - if userInfo, ok := publicUserInfoMap[e.UserID]; ok { - if e.Nickname == "" { - e.Nickname = userInfo.Nickname - } - if e.FaceURL == "" { - e.FaceURL = userInfo.FaceURL - } - } return convert.Db2PbGroupMember(e) }) return resp, nil @@ -1617,7 +1500,7 @@ func (s *groupServer) GetGroupMemberRoleLevel(ctx context.Context, req *pbgroup. func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *pbgroup.GetGroupUsersReqApplicationListReq) (*pbgroup.GetGroupUsersReqApplicationListResp, error) { resp := &pbgroup.GetGroupUsersReqApplicationListResp{} - total, requests, err := s.GroupDatabase.FindGroupRequests(ctx, req.GroupID, req.UserIDs) + requests, err := s.db.FindGroupRequests(ctx, req.GroupID, req.UserIDs) if err != nil { return nil, err } @@ -1627,7 +1510,7 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * groupIDs := utils.Distinct(utils.Slice(requests, func(e *relationtb.GroupRequestModel) string { return e.GroupID })) - groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs) + groups, err := s.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } @@ -1637,14 +1520,17 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if ids := utils.Single(groupIDs, utils.Keys(groupMap)); len(ids) > 0 { return nil, errs.ErrGroupIDNotFound.Wrap(strings.Join(ids, ",")) } - owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) + owners, err := s.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + if err := s.PopulateGroupMember(ctx, owners...); err != nil { + return nil, err + } ownerMap := utils.SliceToMap(owners, func(e *relationtb.GroupMemberModel) string { return e.GroupID }) - groupMemberNum, err := s.GroupDatabase.MapGroupMemberNum(ctx, groupIDs) + groupMemberNum, err := s.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } @@ -1655,40 +1541,6 @@ func (s *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * } return convert.Db2PbGroupRequest(e, nil, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) }) - resp.Total = total + resp.Total = int64(len(resp.GroupRequests)) return resp, nil } - -func (s *groupServer) groupMemberHashCode(ctx context.Context, groupID string) (uint64, error) { - userIDs, err := s.GroupDatabase.FindGroupMemberUserID(ctx, groupID) - if err != nil { - return 0, err - } - var members []*sdkws.GroupMemberFullInfo - if len(userIDs) > 0 { - resp, err := s.GetGroupMembersInfo(ctx, &pbgroup.GetGroupMembersInfoReq{GroupID: groupID, UserIDs: userIDs}) - if err != nil { - return 0, err - } - members = resp.Members - utils.Sort(userIDs, true) - } - memberMap := utils.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { - return e.UserID - }) - res := make([]*sdkws.GroupMemberFullInfo, 0, len(members)) - for _, userID := range userIDs { - member, ok := memberMap[userID] - if !ok { - continue - } - member.AppMangerLevel = 0 - res = append(res, member) - } - data, err := json.Marshal(res) - if err != nil { - return 0, err - } - sum := md5.Sum(data) - return binary.BigEndian.Uint64(sum[:]), nil -} diff --git a/internal/rpc/group/statistics.go b/internal/rpc/group/statistics.go index 8aeefbee33..d909e95035 100644 --- a/internal/rpc/group/statistics.go +++ b/internal/rpc/group/statistics.go @@ -26,16 +26,16 @@ func (s *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCrea if req.Start > req.End { return nil, errs.ErrArgs.Wrap("start > end") } - total, err := s.GroupDatabase.CountTotal(ctx, nil) + total, err := s.db.CountTotal(ctx, nil) if err != nil { return nil, err } start := time.UnixMilli(req.Start) - before, err := s.GroupDatabase.CountTotal(ctx, &start) + before, err := s.db.CountTotal(ctx, &start) if err != nil { return nil, err } - count, err := s.GroupDatabase.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End)) + count, err := s.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End)) if err != nil { return nil, err } diff --git a/internal/rpc/group/super_group.go b/internal/rpc/group/super_group.go index 6cd1a29439..f893a79c23 100644 --- a/internal/rpc/group/super_group.go +++ b/internal/rpc/group/super_group.go @@ -16,99 +16,15 @@ package group import ( "context" - "fmt" - "strings" + "errors" - "github.com/OpenIMSDK/protocol/constant" pbgroup "github.com/OpenIMSDK/protocol/group" - sdkws "github.com/OpenIMSDK/protocol/sdkws" - "github.com/OpenIMSDK/tools/errs" - "github.com/OpenIMSDK/tools/utils" - - "github.com/openimsdk/open-im-server/v3/pkg/common/convert" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) -func (s *groupServer) GetJoinedSuperGroupList( - ctx context.Context, - req *pbgroup.GetJoinedSuperGroupListReq, -) (*pbgroup.GetJoinedSuperGroupListResp, error) { - resp := &pbgroup.GetJoinedSuperGroupListResp{} - groupIDs, err := s.GroupDatabase.FindJoinSuperGroup(ctx, req.UserID) - if err != nil { - return nil, err - } - if len(groupIDs) == 0 { - return resp, nil - } - owners, err := s.FindGroupMember(ctx, groupIDs, nil, []int32{constant.GroupOwner}) - if err != nil { - return nil, err - } - ownerMap := utils.SliceToMap(owners, func(e *relation.GroupMemberModel) string { - return e.GroupID - }) - if ids := utils.Single(groupIDs, utils.Keys(ownerMap)); len(ids) > 0 { - return nil, errs.ErrData.Wrap(fmt.Sprintf("super group %s not owner", strings.Join(ids, ","))) - } - groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs) - if err != nil { - return nil, err - } - groupMap := utils.SliceToMap(groups, func(e *relation.GroupModel) string { - return e.GroupID - }) - if ids := utils.Single(groupIDs, utils.Keys(groupMap)); len(ids) > 0 { - return nil, errs.ErrData.Wrap(fmt.Sprintf("super group info %s not found", strings.Join(ids, ","))) - } - superGroupMembers, err := s.GroupDatabase.FindSuperGroup(ctx, groupIDs) - if err != nil { - return nil, err - } - superGroupMemberMap := utils.SliceToMapAny( - superGroupMembers, - func(e *unrelation.SuperGroupModel) (string, []string) { - return e.GroupID, e.MemberIDs - }, - ) - resp.Groups = utils.Slice(groupIDs, func(groupID string) *sdkws.GroupInfo { - return convert.Db2PbGroupInfo(groupMap[groupID], ownerMap[groupID].UserID, uint32(len(superGroupMemberMap))) - }) - return resp, nil +func (s *groupServer) GetJoinedSuperGroupList(context.Context, *pbgroup.GetJoinedSuperGroupListReq) (*pbgroup.GetJoinedSuperGroupListResp, error) { + return nil, errors.New("deprecated") } -func (s *groupServer) GetSuperGroupsInfo( - ctx context.Context, - req *pbgroup.GetSuperGroupsInfoReq, -) (resp *pbgroup.GetSuperGroupsInfoResp, err error) { - resp = &pbgroup.GetSuperGroupsInfoResp{} - if len(req.GroupIDs) == 0 { - return nil, errs.ErrArgs.Wrap("groupIDs empty") - } - groups, err := s.GroupDatabase.FindGroup(ctx, req.GroupIDs) - if err != nil { - return nil, err - } - superGroupMembers, err := s.GroupDatabase.FindSuperGroup(ctx, req.GroupIDs) - if err != nil { - return nil, err - } - superGroupMemberMap := utils.SliceToMapAny( - superGroupMembers, - func(e *unrelation.SuperGroupModel) (string, []string) { - return e.GroupID, e.MemberIDs - }, - ) - owners, err := s.FindGroupMember(ctx, req.GroupIDs, nil, []int32{constant.GroupOwner}) - if err != nil { - return nil, err - } - ownerMap := utils.SliceToMap(owners, func(e *relation.GroupMemberModel) string { - return e.GroupID - }) - resp.GroupInfos = utils.Slice(groups, func(e *relation.GroupModel) *sdkws.GroupInfo { - return convert.Db2PbGroupInfo(e, ownerMap[e.GroupID].UserID, uint32(len(superGroupMemberMap[e.GroupID]))) - }) - return resp, nil +func (s *groupServer) GetSuperGroupsInfo(context.Context, *pbgroup.GetSuperGroupsInfoReq) (resp *pbgroup.GetSuperGroupsInfoResp, err error) { + return nil, errors.New("deprecated") } diff --git a/internal/rpc/msg/utils.go b/internal/rpc/msg/utils.go index 115df99463..e45d7b3959 100644 --- a/internal/rpc/msg/utils.go +++ b/internal/rpc/msg/utils.go @@ -15,12 +15,11 @@ package msg import ( - "github.com/redis/go-redis/v9" - "gorm.io/gorm" - "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" + "go.mongodb.org/mongo-driver/mongo" "github.com/openimsdk/open-im-server/v3/pkg/common/config" ) @@ -45,7 +44,7 @@ func isMessageHasReadEnabled(msgData *sdkws.MsgData) bool { func IsNotFound(err error) bool { switch utils.Unwrap(err) { - case redis.Nil, gorm.ErrRecordNotFound: + case redis.Nil, mongo.ErrNoDocuments: return true default: return false diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go index aa83f58f77..57d4f536e4 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, @@ -120,7 +120,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) if req.StartTime > req.EndTime { return nil, errs.ErrArgs.Wrap("startTime>endTime") } - total, logs, err := t.thirdDatabase.SearchLogs(ctx, req.Keyword, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime), req.Pagination.PageNumber, req.Pagination.ShowNumber) + total, logs, err := t.thirdDatabase.SearchLogs(ctx, req.Keyword, time.UnixMilli(req.StartTime), time.UnixMilli(req.EndTime), req.Pagination) if err != nil { return nil, err } @@ -128,18 +128,16 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq) for _, log := range logs { userIDs = append(userIDs, log.UserID) } - users, err := t.thirdDatabase.FindUsers(ctx, userIDs) + userMap, err := t.userRpcClient.GetUsersInfoMap(ctx, userIDs) if err != nil { return nil, err } - IDtoName := make(map[string]string) - for _, user := range users { - IDtoName[user.UserID] = user.Nickname - } for _, pbLog := range pbLogs { - pbLog.Nickname = IDtoName[pbLog.UserID] + if user, ok := userMap[pbLog.UserID]; ok { + pbLog.Nickname = user.Nickname + } } resp.LogsInfos = pbLogs - resp.Total = total + resp.Total = uint32(total) return &resp, nil } diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 984af88e16..ca826e8058 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -64,7 +64,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In Key: haErr.Object.Key, Size: haErr.Object.Size, ContentType: req.ContentType, - Cause: req.Cause, + Group: req.Cause, CreateTime: time.Now(), } if err := t.s3dataBase.SetObject(ctx, obj); err != nil { @@ -143,7 +143,7 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co Key: result.Key, Size: result.Size, ContentType: req.ContentType, - Cause: req.Cause, + Group: req.Cause, CreateTime: time.Now(), } if err := t.s3dataBase.SetObject(ctx, obj); err != nil { diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index eed3d4802c..7a63d3526a 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -17,15 +17,17 @@ package third import ( "context" "fmt" - "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" @@ -34,13 +36,22 @@ import ( "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/rpcclient" ) func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { + mongo, err := unrelation.NewMongo() + if err != nil { + return err + } + logdb, err := mgo.NewLogMongo(mongo.GetDatabase()) + if err != nil { + return err + } + s3db, err := mgo.NewS3Mongo(mongo.GetDatabase()) + if err != nil { + return err + } apiURL := config.Config.Object.ApiURL if apiURL == "" { return fmt.Errorf("api url is empty") @@ -56,13 +67,6 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e if err != nil { return err } - db, err := relation.NewGormDB() - if err != nil { - return err - } - if err := db.AutoMigrate(&relationtb.ObjectModel{}); err != nil { - return err - } // 根据配置文件策略选择 oss 方式 enable := config.Config.Object.Enable var o s3.Interface @@ -73,25 +77,17 @@ 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) } if err != nil { return err } - //specialerror.AddErrHandler(func(err error) errs.CodeError { - // if o.IsNotFound(err) { - // return errs.ErrRecordNotFound - // } - // return nil - //}) third.RegisterThirdServer(server, &thirdServer{ apiURL: apiURL, - thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), db), + thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb), userRpcClient: rpcclient.NewUserRpcClient(client), - s3dataBase: controller.NewS3Database(rdb, o, relation.NewObjectInfo(db)), + s3dataBase: controller.NewS3Database(rdb, o, s3db), defaultExpire: time.Hour * 24 * 7, }) return nil diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index f4164dbf25..77da408aa7 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -20,11 +20,14 @@ import ( "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" "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/tools/tx" "github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" @@ -35,7 +38,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/convert" "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" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" @@ -55,10 +57,6 @@ type userServer struct { } func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { - db, err := relation.NewGormDB() - if err != nil { - return err - } rdb, err := cache.NewRedis() if err != nil { return err @@ -67,9 +65,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { if err != nil { return err } - if err := db.AutoMigrate(&tablerelation.UserModel{}); err != nil { - return err - } users := make([]*tablerelation.UserModel, 0) if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) { return errors.New("len(config.Config.Manager.AppManagerUid) != len(config.Config.Manager.Nickname)") @@ -77,10 +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 := relation.NewUserGorm(db) + 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.NewGorm(db), userMongoDB) + database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB) friendRpcClient := rpcclient.NewFriendRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) @@ -118,12 +116,8 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { return nil, err } - user := convert.UserPb2DB(req.UserInfo) - if err != nil { - return nil, err - } - err = s.Update(ctx, user) - if err != nil { + data := convert.UserPb2DBMap(req.UserInfo) + if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil { return nil, err } _ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) @@ -153,7 +147,7 @@ func (s *userServer) SetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Se if _, err := s.FindWithError(ctx, []string{req.UserID}); err != nil { return nil, err } - m := make(map[string]interface{}, 1) + m := make(map[string]any, 1) m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt if err := s.UpdateByMap(ctx, req.UserID, m); err != nil { return nil, err @@ -175,7 +169,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR if err != nil { return nil, err } - userIDs := make(map[string]interface{}, 0) + userIDs := make(map[string]any, 0) for _, v := range users { userIDs[v.UserID] = nil } @@ -192,12 +186,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR } func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPaginationUsersReq) (resp *pbuser.GetPaginationUsersResp, err error) { - var pageNumber, showNumber int32 - if req.Pagination != nil { - pageNumber = req.Pagination.PageNumber - showNumber = req.Pagination.ShowNumber - } - users, total, err := s.Page(ctx, pageNumber, showNumber) + total, users, err := s.Page(ctx, req.Pagination) if err != nil { return nil, err } @@ -269,11 +258,11 @@ func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Ge // GetAllUserID Get user account by page. func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) { - userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination.PageNumber, req.Pagination.ShowNumber) + total, userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination) if err != nil { return nil, err } - return &pbuser.GetAllUserIDResp{UserIDs: userIDs}, nil + return &pbuser.GetAllUserIDResp{Total: int32(total), UserIDs: userIDs}, nil } // SubscribeOrCancelUsersStatus Subscribe online or cancel online users. diff --git a/internal/tools/conversation.go b/internal/tools/conversation.go index 05d963a175..0d02753393 100644 --- a/internal/tools/conversation.go +++ b/internal/tools/conversation.go @@ -19,6 +19,8 @@ import ( "math/rand" "time" + "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/utils" @@ -91,7 +93,11 @@ func (c *MsgTool) ConversationsDestructMsgs() { } for i := 0; i < count; i++ { pageNumber := rand.Int63() % maxPage - conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, int32(pageNumber), batchNum) + pagination := &sdkws.RequestPagination{ + PageNumber: int32(pageNumber), + ShowNumber: batchNum, + } + conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination) if err != nil { log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) continue @@ -133,7 +139,7 @@ func (c *MsgTool) ConversationsDestructMsgs() { continue } if len(seqs) > 0 { - if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err != nil { + if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID) continue } diff --git a/internal/tools/msg.go b/internal/tools/msg.go index ad8f5c4717..97bb2988e7 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -19,6 +19,11 @@ import ( "fmt" "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" @@ -31,13 +36,11 @@ import ( "github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mw" - "github.com/OpenIMSDK/tools/tx" "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/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" @@ -72,33 +75,45 @@ func InitMsgTool() (*MsgTool, error) { if err != nil { return nil, err } - db, err := relation.NewGormDB() + discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) if err != nil { return nil, err } - discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) - /* - discov, err := zookeeper.NewClient(config.Config.Zookeeper.ZkAddr, config.Config.Zookeeper.Schema, - zookeeper.WithFreq(time.Hour), zookeeper.WithRoundRobin(), zookeeper.WithUserNameAndPassword(config.Config.Zookeeper.Username, - config.Config.Zookeeper.Password), zookeeper.WithTimeout(10), zookeeper.WithLogger(log.NewZkLogger()))*/ + discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) + userDB, err := mgo.NewUserMongo(mongo.GetDatabase()) if err != nil { return nil, err } - discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) - userDB := relation.NewUserGorm(db) msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) + ctxTx := tx.NewMongo(mongo.GetClient()) userDatabase := controller.NewUserDatabase( userDB, - cache.NewUserCacheRedis(rdb, relation.NewUserGorm(db), cache.GetDefaultOpt()), - tx.NewGorm(db), + cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()), + ctxTx, userMongoDB, ) - groupDatabase := controller.InitGroupDatabase(db, rdb, mongo.GetDatabase(), nil) + groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) + if err != nil { + return nil, err + } + groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) + if err != nil { + return nil, err + } + groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) + if err != nil { + return nil, err + } + conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) + if err != nil { + return nil, err + } + groupDatabase := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, ctxTx, nil) conversationDatabase := controller.NewConversationDatabase( - relation.NewConversationGorm(db), - cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), relation.NewConversationGorm(db)), - tx.NewGorm(db), + conversationDB, + cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), + ctxTx, ) msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) @@ -144,7 +159,11 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() { } for i := 0; i < count; i++ { pageNumber := rand.Int63() % maxPage - conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, int32(pageNumber), batchNum) + pagination := &sdkws.RequestPagination{ + PageNumber: int32(pageNumber), + ShowNumber: batchNum, + } + conversationIDs, err := c.conversationDatabase.PageConversationIDs(ctx, pagination) if err != nil { log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) continue diff --git a/internal/tools/msg_doc_convert.go b/internal/tools/msg_doc_convert.go index 758625be1a..b9150c3623 100644 --- a/internal/tools/msg_doc_convert.go +++ b/internal/tools/msg_doc_convert.go @@ -32,7 +32,7 @@ func (c *MsgTool) convertTools() { for _, conversationID := range conversationIDs { conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID)) } - userIDs, err := c.userDatabase.GetAllUserID(ctx, 0, 0) + _, userIDs, err := c.userDatabase.GetAllUserID(ctx, nil) if err != nil { log.ZError(ctx, "get all user ids failed", err) return diff --git a/pkg/apistruct/manage.go b/pkg/apistruct/manage.go index 1e0ab3214f..a48f5253c6 100644 --- a/pkg/apistruct/manage.go +++ b/pkg/apistruct/manage.go @@ -36,7 +36,7 @@ type SendMsg struct { SenderPlatformID int32 `json:"senderPlatformID"` // Content is the actual content of the message, required and excluded from Swagger documentation. - Content map[string]interface{} `json:"content" binding:"required" swaggerignore:"true"` + Content map[string]any `json:"content" binding:"required" swaggerignore:"true"` // ContentType is an integer that represents the type of the content. ContentType int32 `json:"contentType" binding:"required"` diff --git a/pkg/authverify/token.go b/pkg/authverify/token.go index a8e577fdea..fd01e8c5a6 100644 --- a/pkg/authverify/token.go +++ b/pkg/authverify/token.go @@ -28,7 +28,7 @@ import ( ) func Secret() jwt.Keyfunc { - return func(token *jwt.Token) (interface{}, error) { + return func(token *jwt.Token) (any, error) { return []byte(config.Config.Secret), nil } } @@ -55,7 +55,7 @@ func CheckAdmin(ctx context.Context) error { return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) } -func ParseRedisInterfaceToken(redisToken interface{}) (*tokenverify.Claims, error) { +func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) { return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret()) } diff --git a/pkg/common/cmd/rpc.go b/pkg/common/cmd/rpc.go index 6266c03b2f..ea2a00b078 100644 --- a/pkg/common/cmd/rpc.go +++ b/pkg/common/cmd/rpc.go @@ -46,15 +46,13 @@ func (a *RpcCmd) Exec() error { return a.Execute() } -func (a *RpcCmd) StartSvr( - name string, - rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error, -) error { +func (a *RpcCmd) StartSvr(name string, rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error { if a.GetPortFlag() == 0 { return errors.New("port is required") } return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn) } + func (a *RpcCmd) GetPortFromConfig(portType string) int { switch a.Name { case RpcPushServer: diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 3c819ea2c4..5fb8fe7e21 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -44,6 +44,18 @@ type POfflinePush struct { Ext string `yaml:"ext"` } +type MYSQL struct { + Address []string `yaml:"address"` + Username string `yaml:"username"` + Password string `yaml:"password"` + Database string `yaml:"database"` + MaxOpenConn int `yaml:"maxOpenConn"` + MaxIdleConn int `yaml:"maxIdleConn"` + MaxLifeTime int `yaml:"maxLifeTime"` + LogLevel int `yaml:"logLevel"` + SlowThreshold int `yaml:"slowThreshold"` +} + type configStruct struct { Envs struct { Discovery string `yaml:"discovery"` @@ -55,17 +67,7 @@ type configStruct struct { Password string `yaml:"password"` } `yaml:"zookeeper"` - Mysql struct { - Address []string `yaml:"address"` - Username string `yaml:"username"` - Password string `yaml:"password"` - Database string `yaml:"database"` - MaxOpenConn int `yaml:"maxOpenConn"` - MaxIdleConn int `yaml:"maxIdleConn"` - MaxLifeTime int `yaml:"maxLifeTime"` - LogLevel int `yaml:"logLevel"` - SlowThreshold int `yaml:"slowThreshold"` - } `yaml:"mysql"` + Mysql *MYSQL `yaml:"mysql"` Mongo struct { Uri string `yaml:"uri"` diff --git a/pkg/common/config/parse.go b/pkg/common/config/parse.go index f2ea962ee8..22e458e006 100644 --- a/pkg/common/config/parse.go +++ b/pkg/common/config/parse.go @@ -71,7 +71,7 @@ func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options { return opts } -func initConfig(config interface{}, configName, configFolderPath string) error { +func initConfig(config any, configName, configFolderPath string) error { configFolderPath = filepath.Join(configFolderPath, configName) _, err := os.Stat(configFolderPath) if err != nil { diff --git a/pkg/common/config/parse_test.go b/pkg/common/config/parse_test.go index e34aa5b7fa..38171ec088 100644 --- a/pkg/common/config/parse_test.go +++ b/pkg/common/config/parse_test.go @@ -76,7 +76,7 @@ func TestGetOptionsByNotification(t *testing.T) { func Test_initConfig(t *testing.T) { type args struct { - config interface{} + config any configName string configFolderPath string } diff --git a/pkg/common/convert/friend.go b/pkg/common/convert/friend.go index 7003c8aa66..c81cd98d60 100644 --- a/pkg/common/convert/friend.go +++ b/pkg/common/convert/friend.go @@ -16,6 +16,7 @@ package convert import ( "context" + "fmt" "github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/tools/utils" @@ -31,23 +32,22 @@ func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel { return dbFriend } -func FriendDB2Pb( - ctx context.Context, - friendDB *relation.FriendModel, +func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), ) (*sdkws.FriendInfo, error) { - pbfriend := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} - utils.CopyStructFields(pbfriend, friendDB) users, err := getUsers(ctx, []string{friendDB.FriendUserID}) if err != nil { return nil, err } - pbfriend.FriendUser.UserID = users[friendDB.FriendUserID].UserID - pbfriend.FriendUser.Nickname = users[friendDB.FriendUserID].Nickname - pbfriend.FriendUser.FaceURL = users[friendDB.FriendUserID].FaceURL - pbfriend.FriendUser.Ex = users[friendDB.FriendUserID].Ex - pbfriend.CreateTime = friendDB.CreateTime.Unix() - return pbfriend, nil + user, ok := users[friendDB.FriendUserID] + if !ok { + return nil, fmt.Errorf("user not found: %s", friendDB.FriendUserID) + } + + return &sdkws.FriendInfo{ + FriendUser: user, + CreateTime: friendDB.CreateTime.Unix(), + }, nil } func FriendsDB2Pb( @@ -118,3 +118,37 @@ func FriendRequestDB2Pb( } return res, nil } + +// FriendPb2DBMap converts a FriendInfo protobuf object to a map suitable for database operations. +// It only includes non-zero or non-empty fields in the map. +func FriendPb2DBMap(friend *sdkws.FriendInfo) map[string]any { + if friend == nil { + return nil + } + + val := make(map[string]any) + + // Assuming FriendInfo has similar fields to those in FriendModel. + // Add or remove fields based on your actual FriendInfo and FriendModel structures. + if friend.FriendUser != nil { + if friend.FriendUser.UserID != "" { + val["friend_user_id"] = friend.FriendUser.UserID + } + if friend.FriendUser.Nickname != "" { + val["nickname"] = friend.FriendUser.Nickname + } + if friend.FriendUser.FaceURL != "" { + val["face_url"] = friend.FriendUser.FaceURL + } + if friend.FriendUser.Ex != "" { + val["ex"] = friend.FriendUser.Ex + } + } + if friend.CreateTime != 0 { + val["create_time"] = friend.CreateTime // You might need to convert this to a proper time format. + } + + // Include other fields from FriendInfo as needed, similar to the above pattern. + + return val +} diff --git a/pkg/common/convert/user.go b/pkg/common/convert/user.go index 4ca1899bef..0c71aac22d 100644 --- a/pkg/common/convert/user.go +++ b/pkg/common/convert/user.go @@ -16,32 +16,58 @@ package convert import ( "github.com/OpenIMSDK/protocol/sdkws" + "time" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) -func UsersDB2Pb(users []*relationtb.UserModel) (result []*sdkws.UserInfo) { +func UsersDB2Pb(users []*relationtb.UserModel) []*sdkws.UserInfo { + result := make([]*sdkws.UserInfo, 0, len(users)) for _, user := range users { - var userPb sdkws.UserInfo - userPb.UserID = user.UserID - userPb.Nickname = user.Nickname - userPb.FaceURL = user.FaceURL - userPb.Ex = user.Ex - userPb.CreateTime = user.CreateTime.UnixMilli() - userPb.AppMangerLevel = user.AppMangerLevel - userPb.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt - result = append(result, &userPb) + userPb := &sdkws.UserInfo{ + UserID: user.UserID, + Nickname: user.Nickname, + FaceURL: user.FaceURL, + Ex: user.Ex, + CreateTime: user.CreateTime.UnixMilli(), + AppMangerLevel: user.AppMangerLevel, + GlobalRecvMsgOpt: user.GlobalRecvMsgOpt, + } + result = append(result, userPb) } return result } func UserPb2DB(user *sdkws.UserInfo) *relationtb.UserModel { - var userDB relationtb.UserModel - userDB.UserID = user.UserID - userDB.Nickname = user.Nickname - userDB.FaceURL = user.FaceURL - userDB.Ex = user.Ex - userDB.AppMangerLevel = user.AppMangerLevel - userDB.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt - return &userDB + return &relationtb.UserModel{ + UserID: user.UserID, + Nickname: user.Nickname, + FaceURL: user.FaceURL, + Ex: user.Ex, + CreateTime: time.UnixMilli(user.CreateTime), + AppMangerLevel: user.AppMangerLevel, + GlobalRecvMsgOpt: user.GlobalRecvMsgOpt, + } +} + +func UserPb2DBMap(user *sdkws.UserInfo) map[string]any { + if user == nil { + return nil + } + val := make(map[string]any) + fields := map[string]any{ + "nickname": user.Nickname, + "face_url": user.FaceURL, + "ex": user.Ex, + "app_manager_level": user.AppMangerLevel, + "global_recv_msg_opt": user.GlobalRecvMsgOpt, + } + for key, value := range fields { + if v, ok := value.(string); ok && v != "" { + val[key] = v + } else if v, ok := value.(int32); ok && v != 0 { + val[key] = v + } + } + return val } diff --git a/pkg/common/convert/user_test.go b/pkg/common/convert/user_test.go new file mode 100644 index 0000000000..a24efb53cc --- /dev/null +++ b/pkg/common/convert/user_test.go @@ -0,0 +1,87 @@ +// 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 convert + +import ( + "reflect" + "testing" + + "github.com/OpenIMSDK/protocol/sdkws" + + relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" +) + +func TestUsersDB2Pb(t *testing.T) { + type args struct { + users []*relationtb.UserModel + } + tests := []struct { + name string + args args + wantResult []*sdkws.UserInfo + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotResult := UsersDB2Pb(tt.args.users); !reflect.DeepEqual(gotResult, tt.wantResult) { + t.Errorf("UsersDB2Pb() = %v, want %v", gotResult, tt.wantResult) + } + }) + } +} + +func TestUserPb2DB(t *testing.T) { + type args struct { + user *sdkws.UserInfo + } + tests := []struct { + name string + args args + want *relationtb.UserModel + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := UserPb2DB(tt.args.user); !reflect.DeepEqual(got, tt.want) { + t.Errorf("UserPb2DB() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUserPb2DBMap(t *testing.T) { + user := &sdkws.UserInfo{ + Nickname: "TestUser", + FaceURL: "http://openim.io/logo.jpg", + Ex: "Extra Data", + AppMangerLevel: 1, + GlobalRecvMsgOpt: 2, + } + + expected := map[string]any{ + "nickname": "TestUser", + "face_url": "http://openim.io/logo.jpg", + "ex": "Extra Data", + "app_manager_level": int32(1), + "global_recv_msg_opt": int32(2), + } + + result := UserPb2DBMap(user) + if !reflect.DeepEqual(result, expected) { + t.Errorf("UserPb2DBMap returned unexpected map. Got %v, want %v", result, expected) + } +} diff --git a/pkg/common/db/cache/conversation.go b/pkg/common/db/cache/conversation.go index 9c0bcfae4a..a7018bc18c 100644 --- a/pkg/common/db/cache/conversation.go +++ b/pkg/common/db/cache/conversation.go @@ -26,7 +26,6 @@ import ( "github.com/OpenIMSDK/tools/utils" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) @@ -67,10 +66,10 @@ type ConversationCache interface { GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache // get one super group recv msg but do not notification userID list - GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) + //GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache // get one super group recv msg but do not notification userID list hash - GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) + //GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) @@ -101,20 +100,20 @@ type ConversationRedisCache struct { expireTime time.Duration } -func NewNewConversationRedis( - rdb redis.UniversalClient, - conversationDB *relation.ConversationGorm, - options rockscache.Options, -) ConversationCache { - rcClient := rockscache.NewClient(rdb, options) - - return &ConversationRedisCache{ - rcClient: rcClient, - metaCache: NewMetaCacheRedis(rcClient), - conversationDB: conversationDB, - expireTime: conversationExpireTime, - } -} +//func NewNewConversationRedis( +// rdb redis.UniversalClient, +// conversationDB *relation.ConversationGorm, +// options rockscache.Options, +//) ConversationCache { +// rcClient := rockscache.NewClient(rdb, options) +// +// return &ConversationRedisCache{ +// rcClient: rcClient, +// metaCache: NewMetaCacheRedis(rcClient), +// conversationDB: conversationDB, +// expireTime: conversationExpireTime, +// } +//} func (c *ConversationRedisCache) NewCache() ConversationCache { return &ConversationRedisCache{ @@ -282,11 +281,11 @@ func (c *ConversationRedisCache) GetUserRecvMsgOpt(ctx context.Context, ownerUse }) } -func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) { - return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) { - return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) - }) -} +//func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) { +// return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) { +// return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) +// }) +//} func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache { keys := make([]string, 0, len(ownerUserIDs)) @@ -313,19 +312,19 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID st return cache } -func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { - return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) { - userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) - if err != nil { - return 0, err - } - utils.Sort(userIDs, true) - bi := big.NewInt(0) - bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16) - return bi.Uint64(), nil - }, - ) -} +//func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { +// return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) { +// userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) +// if err != nil { +// return 0, err +// } +// utils.Sort(userIDs, true) +// bi := big.NewInt(0) +// bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16) +// return bi.Uint64(), nil +// }, +// ) +//} func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache { cache := c.NewCache() diff --git a/pkg/common/db/cache/friend.go b/pkg/common/db/cache/friend.go index 64a3589846..1708f76640 100644 --- a/pkg/common/db/cache/friend.go +++ b/pkg/common/db/cache/friend.go @@ -33,19 +33,20 @@ const ( friendKey = "FRIEND_INFO:" ) -// args fn will exec when no data in msgCache. +// FriendCache is an interface for caching friend-related data. type FriendCache interface { metaCache NewCache() FriendCache GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) - // call when friendID List changed + // Called when friendID list changed DelFriendIDs(ownerUserID ...string) FriendCache - // get single friendInfo from msgCache + // Get single friendInfo from the cache GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.FriendModel, err error) - // del friend when friend info changed + // Delete friend when friend info changed DelFriend(ownerUserID, friendUserID string) FriendCache } +// FriendCacheRedis is an implementation of the FriendCache interface using Redis. type FriendCacheRedis struct { metaCache friendDB relationtb.FriendModelInterface @@ -53,6 +54,7 @@ type FriendCacheRedis struct { rcClient *rockscache.Client } +// NewFriendCacheRedis creates a new instance of FriendCacheRedis. func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface, options rockscache.Options) FriendCache { rcClient := rockscache.NewClient(rdb, options) @@ -64,6 +66,7 @@ func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendMo } } +// NewCache creates a new instance of FriendCacheRedis with the same configuration. func (f *FriendCacheRedis) NewCache() FriendCache { return &FriendCacheRedis{ rcClient: f.rcClient, @@ -73,24 +76,29 @@ func (f *FriendCacheRedis) NewCache() FriendCache { } } +// getFriendIDsKey returns the key for storing friend IDs in the cache. func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string { return friendIDsKey + ownerUserID } +// getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache. func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string { return TwoWayFriendsIDsKey + ownerUserID } +// getFriendKey returns the key for storing friend info in the cache. func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string { return friendKey + ownerUserID + "-" + friendUserID } +// GetFriendIDs retrieves friend IDs from the cache or the database if not found. func (f *FriendCacheRedis) GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) { return getCache(ctx, f.rcClient, f.getFriendIDsKey(ownerUserID), f.expireTime, func(ctx context.Context) ([]string, error) { return f.friendDB.FindFriendUserIDs(ctx, ownerUserID) }) } +// DelFriendIDs deletes friend IDs from the cache. func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache { newGroupCache := f.NewCache() keys := make([]string, 0, len(ownerUserIDs)) @@ -102,7 +110,7 @@ func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache { return newGroupCache } -// todo. +// GetTwoWayFriendIDs retrieves two-way friend IDs from the cache. func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID string) (twoWayFriendIDs []string, err error) { friendIDs, err := f.GetFriendIDs(ctx, ownerUserID) if err != nil { @@ -121,6 +129,7 @@ func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID s return twoWayFriendIDs, nil } +// DelTwoWayFriendIDs deletes two-way friend IDs from the cache. func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) FriendCache { newFriendCache := f.NewCache() newFriendCache.AddKeys(f.getTwoWayFriendsIDsKey(ownerUserID)) @@ -128,14 +137,15 @@ func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID s return newFriendCache } -func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, - friendUserID string) (friend *relationtb.FriendModel, err error) { +// GetFriend retrieves friend info from the cache or the database if not found. +func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.FriendModel, err error) { return getCache(ctx, f.rcClient, f.getFriendKey(ownerUserID, friendUserID), f.expireTime, func(ctx context.Context) (*relationtb.FriendModel, error) { return f.friendDB.Take(ctx, ownerUserID, friendUserID) }) } +// DelFriend deletes friend info from the cache. func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) FriendCache { newFriendCache := f.NewCache() newFriendCache.AddKeys(f.getFriendKey(ownerUserID, friendUserID)) diff --git a/pkg/common/db/cache/group.go b/pkg/common/db/cache/group.go index 6a4b578138..603d8e534a 100644 --- a/pkg/common/db/cache/group.go +++ b/pkg/common/db/cache/group.go @@ -16,8 +16,13 @@ package cache import ( "context" + "fmt" + "strconv" "time" + "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/tools/errs" + "github.com/OpenIMSDK/tools/log" "github.com/dtm-labs/rockscache" @@ -26,21 +31,24 @@ import ( "github.com/OpenIMSDK/tools/utils" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" ) const ( - groupExpireTime = time.Second * 60 * 60 * 12 - groupInfoKey = "GROUP_INFO:" - groupMemberIDsKey = "GROUP_MEMBER_IDS:" - groupMembersHashKey = "GROUP_MEMBERS_HASH2:" - groupMemberInfoKey = "GROUP_MEMBER_INFO:" - joinedSuperGroupsKey = "JOIN_SUPER_GROUPS:" - SuperGroupMemberIDsKey = "SUPER_GROUP_MEMBER_IDS:" - joinedGroupsKey = "JOIN_GROUPS_KEY:" - groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" + groupExpireTime = time.Second * 60 * 60 * 12 + groupInfoKey = "GROUP_INFO:" + groupMemberIDsKey = "GROUP_MEMBER_IDS:" + groupMembersHashKey = "GROUP_MEMBERS_HASH2:" + groupMemberInfoKey = "GROUP_MEMBER_INFO:" + //groupOwnerInfoKey = "GROUP_OWNER_INFO:" + joinedGroupsKey = "JOIN_GROUPS_KEY:" + groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" + groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" ) +type GroupHash interface { + GetGroupHash(ctx context.Context, groupID string) (uint64, error) +} + type GroupCache interface { metaCache NewCache() GroupCache @@ -48,11 +56,6 @@ type GroupCache interface { GetGroupInfo(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) DelGroupsInfo(groupIDs ...string) GroupCache - GetJoinedSuperGroupIDs(ctx context.Context, userID string) (joinedSuperGroupIDs []string, err error) - DelJoinedSuperGroupIDs(userIDs ...string) GroupCache - GetSuperGroupMemberIDs(ctx context.Context, groupIDs ...string) (models []*unrelationtb.SuperGroupModel, err error) - DelSuperGroupMemberIDs(groupIDs ...string) GroupCache - GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) DelGroupMembersHash(groupID string) GroupCache @@ -69,9 +72,16 @@ type GroupCache interface { GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*relationtb.GroupMemberModel, err error) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) GetGroupMembersPage(ctx context.Context, groupID string, userID []string, showNumber, pageNumber int32) (total uint32, groupMembers []*relationtb.GroupMemberModel, err error) + FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*relationtb.GroupMemberModel, error) + GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + GetGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) + GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) + DelGroupRoleLevel(groupID string, roleLevel []int32) GroupCache + DelGroupAllRoleLevel(groupID string) GroupCache DelGroupMembersInfo(groupID string, userID ...string) GroupCache - + GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*relationtb.GroupMemberModel, error) + GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error) DelGroupsMemberNum(groupID ...string) GroupCache } @@ -81,10 +91,9 @@ type GroupCacheRedis struct { groupDB relationtb.GroupModelInterface groupMemberDB relationtb.GroupMemberModelInterface groupRequestDB relationtb.GroupRequestModelInterface - mongoDB unrelationtb.SuperGroupModelInterface expireTime time.Duration rcClient *rockscache.Client - hashCode func(ctx context.Context, groupID string) (uint64, error) + groupHash GroupHash } func NewGroupCacheRedis( @@ -92,8 +101,7 @@ func NewGroupCacheRedis( groupDB relationtb.GroupModelInterface, groupMemberDB relationtb.GroupMemberModelInterface, groupRequestDB relationtb.GroupRequestModelInterface, - mongoClient unrelationtb.SuperGroupModelInterface, - hashCode func(ctx context.Context, groupID string) (uint64, error), + hashCode GroupHash, opts rockscache.Options, ) GroupCache { rcClient := rockscache.NewClient(rdb, opts) @@ -101,8 +109,7 @@ func NewGroupCacheRedis( return &GroupCacheRedis{ rcClient: rcClient, expireTime: groupExpireTime, groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, - mongoDB: mongoClient, - hashCode: hashCode, + groupHash: hashCode, metaCache: NewMetaCacheRedis(rcClient), } } @@ -114,7 +121,6 @@ func (g *GroupCacheRedis) NewCache() GroupCache { groupDB: g.groupDB, groupMemberDB: g.groupMemberDB, groupRequestDB: g.groupRequestDB, - mongoDB: g.mongoDB, metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), } } @@ -123,18 +129,10 @@ func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string { return groupInfoKey + groupID } -func (g *GroupCacheRedis) getJoinedSuperGroupsIDKey(userID string) string { - return joinedSuperGroupsKey + userID -} - func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string { return joinedGroupsKey + userID } -func (g *GroupCacheRedis) getSuperGroupMemberIDsKey(groupID string) string { - return SuperGroupMemberIDsKey + groupID -} - func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string { return groupMembersHashKey + groupID } @@ -151,6 +149,10 @@ func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string { return groupMemberNumKey + groupID } +func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { + return groupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel)) +} + func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) { key := g.getGroupInfoKey(group.GroupID) for i, _key := range keys { @@ -173,15 +175,7 @@ func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *relationtb.GroupMembe return 0, errIndex } -// / groupInfo. func (g *GroupCacheRedis) GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) { - //var keys []string - //for _, group := range groupIDs { - // keys = append(keys, g.getGroupInfoKey(group)) - //} - //return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupIndex, func(ctx context.Context) ([]*relationtb.GroupModel, error) { - // return g.groupDB.Find(ctx, groupIDs) - //}) return batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { return g.getGroupInfoKey(groupID) }, func(ctx context.Context, groupID string) (*relationtb.GroupModel, error) { @@ -206,123 +200,44 @@ func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) GroupCache { return newGroupCache } -func (g *GroupCacheRedis) GetJoinedSuperGroupIDs(ctx context.Context, userID string) (joinedSuperGroupIDs []string, err error) { - return getCache(ctx, g.rcClient, g.getJoinedSuperGroupsIDKey(userID), g.expireTime, func(ctx context.Context) ([]string, error) { - userGroup, err := g.mongoDB.GetSuperGroupByUserID(ctx, userID) - if err != nil { - return nil, err - } - return userGroup.GroupIDs, nil - }, - ) -} - -func (g *GroupCacheRedis) GetSuperGroupMemberIDs(ctx context.Context, groupIDs ...string) (models []*unrelationtb.SuperGroupModel, err error) { - //var keys []string - //for _, group := range groupIDs { - // keys = append(keys, g.getSuperGroupMemberIDsKey(group)) - //} - //return batchGetCache(ctx, g.rcClient, keys, g.expireTime, func(model *unrelationtb.SuperGroupModel, keys []string) (int, error) { - // for i, key := range keys { - // if g.getSuperGroupMemberIDsKey(model.GroupID) == key { - // return i, nil - // } - // } - // return 0, errIndex - //}, - // func(ctx context.Context) ([]*unrelationtb.SuperGroupModel, error) { - // return g.mongoDB.FindSuperGroup(ctx, groupIDs) - // }) - return batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { - return g.getSuperGroupMemberIDsKey(groupID) - }, func(ctx context.Context, groupID string) (*unrelationtb.SuperGroupModel, error) { - return g.mongoDB.TakeSuperGroup(ctx, groupID) - }) -} - -// userJoinSuperGroup. -func (g *GroupCacheRedis) DelJoinedSuperGroupIDs(userIDs ...string) GroupCache { +func (g *GroupCacheRedis) DelGroupsOwner(groupIDs ...string) GroupCache { newGroupCache := g.NewCache() - keys := make([]string, 0, len(userIDs)) - for _, userID := range userIDs { - keys = append(keys, g.getJoinedSuperGroupsIDKey(userID)) + keys := make([]string, 0, len(groupIDs)) + for _, groupID := range groupIDs { + keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, constant.GroupOwner)) } newGroupCache.AddKeys(keys...) return newGroupCache } -func (g *GroupCacheRedis) DelSuperGroupMemberIDs(groupIDs ...string) GroupCache { +func (g *GroupCacheRedis) DelGroupRoleLevel(groupID string, roleLevels []int32) GroupCache { newGroupCache := g.NewCache() - keys := make([]string, 0, len(groupIDs)) - for _, groupID := range groupIDs { - keys = append(keys, g.getSuperGroupMemberIDsKey(groupID)) + keys := make([]string, 0, len(roleLevels)) + for _, roleLevel := range roleLevels { + keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, roleLevel)) } newGroupCache.AddKeys(keys...) - return newGroupCache } -// groupMembersHash. +func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) GroupCache { + return g.DelGroupRoleLevel(groupID, []int32{constant.GroupOwner, constant.GroupAdmin, constant.GroupOrdinaryUsers}) +} + func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) { + if g.groupHash == nil { + return 0, errs.ErrInternalServer.Wrap("group hash is nil") + } return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) { - return g.hashCode(ctx, groupID) + return g.groupHash.GetGroupHash(ctx, groupID) }) - - //return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, - // func(ctx context.Context) (uint64, error) { - // userIDs, err := g.GetGroupMemberIDs(ctx, groupID) - // if err != nil { - // return 0, err - // } - // log.ZInfo(ctx, "GetGroupMembersHash", "groupID", groupID, "userIDs", userIDs) - // var members []*relationtb.GroupMemberModel - // if len(userIDs) > 0 { - // members, err = g.GetGroupMembersInfo(ctx, groupID, userIDs) - // if err != nil { - // return 0, err - // } - // utils.Sort(userIDs, true) - // } - // memberMap := make(map[string]*relationtb.GroupMemberModel) - // for i, member := range members { - // memberMap[member.UserID] = members[i] - // } - // data := make([]string, 0, len(members)*11) - // for _, userID := range userIDs { - // member, ok := memberMap[userID] - // if !ok { - // continue - // } - // data = append(data, - // member.GroupID, - // member.UserID, - // member.Nickname, - // member.FaceURL, - // strconv.Itoa(int(member.RoleLevel)), - // strconv.FormatInt(member.JoinTime.UnixMilli(), 10), - // strconv.Itoa(int(member.JoinSource)), - // member.InviterUserID, - // member.OperatorUserID, - // strconv.FormatInt(member.MuteEndTime.UnixMilli(), 10), - // member.Ex, - // ) - // } - // log.ZInfo(ctx, "hash data info", "userIDs.len", len(userIDs), "hash.data.len", len(data)) - // log.ZInfo(ctx, "json hash data", "groupID", groupID, "data", data) - // val, err := json.Marshal(data) - // if err != nil { - // return 0, err - // } - // sum := md5.Sum(val) - // code := binary.BigEndian.Uint64(sum[:]) - // log.ZInfo(ctx, "GetGroupMembersHash", "groupID", groupID, "hashCode", code, "num", len(members)) - // return code, nil - // }, - //) } func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) { + if g.groupHash == nil { + return nil, errs.ErrInternalServer.Wrap("group hash is nil") + } res := make(map[string]*relationtb.GroupSimpleUserID) for _, groupID := range groupIDs { hash, err := g.GetGroupMembersHash(ctx, groupID) @@ -347,7 +262,6 @@ func (g *GroupCacheRedis) DelGroupMembersHash(groupID string) GroupCache { return cache } -// groupMemberIDs. func (g *GroupCacheRedis) GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error) { return getCache(ctx, g.rcClient, g.getGroupMemberIDsKey(groupID), g.expireTime, func(ctx context.Context) ([]string, error) { return g.groupMemberDB.FindMemberUserID(ctx, groupID) @@ -398,13 +312,6 @@ func (g *GroupCacheRedis) GetGroupMemberInfo(ctx context.Context, groupID, userI } func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupMemberModel, error) { - //var keys []string - //for _, userID := range userIDs { - // keys = append(keys, g.getGroupMemberInfoKey(groupID, userID)) - //} - //return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupMemberIndex, func(ctx context.Context) ([]*relationtb.GroupMemberModel, error) { - // return g.groupMemberDB.Find(ctx, []string{groupID}, userIDs, nil) - //}) return batchGetCache2(ctx, g.rcClient, g.expireTime, userIDs, func(userID string) string { return g.getGroupMemberInfoKey(groupID, userID) }, func(ctx context.Context, userID string) (*relationtb.GroupMemberModel, error) { @@ -446,13 +353,6 @@ func (g *GroupCacheRedis) GetAllGroupMemberInfo(ctx context.Context, groupID str if err != nil { return nil, err } - //var keys []string - //for _, groupMemberID := range groupMemberIDs { - // keys = append(keys, g.getGroupMemberInfoKey(groupID, groupMemberID)) - //} - //return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupMemberIndex, func(ctx context.Context) ([]*relationtb.GroupMemberModel, error) { - // return g.groupMemberDB.Find(ctx, []string{groupID}, groupMemberIDs, nil) - //}) return g.GetGroupMembersInfo(ctx, groupID, groupMemberIDs) } @@ -483,3 +383,68 @@ func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) GroupCache { return cache } + +func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { + members, err := g.GetGroupRoleLevelMemberInfo(ctx, groupID, constant.GroupOwner) + if err != nil { + return nil, err + } + if len(members) == 0 { + return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("group %s owner not found", groupID)) + } + return members[0], nil +} + +func (g *GroupCacheRedis) GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) { + members := make([]*relationtb.GroupMemberModel, 0, len(groupIDs)) + for _, groupID := range groupIDs { + items, err := g.GetGroupRoleLevelMemberInfo(ctx, groupID, constant.GroupOwner) + if err != nil { + return nil, err + } + if len(items) > 0 { + members = append(members, items[0]) + } + } + return members, nil +} + +func (g *GroupCacheRedis) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) { + return getCache(ctx, g.rcClient, g.getGroupRoleLevelMemberIDsKey(groupID, roleLevel), g.expireTime, func(ctx context.Context) ([]string, error) { + return g.groupMemberDB.FindRoleLevelUserIDs(ctx, groupID, roleLevel) + }) +} + +func (g *GroupCacheRedis) GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*relationtb.GroupMemberModel, error) { + userIDs, err := g.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) + if err != nil { + return nil, err + } + return g.GetGroupMembersInfo(ctx, groupID, userIDs) +} + +func (g *GroupCacheRedis) GetGroupRolesLevelMemberInfo(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { + var userIDs []string + for _, roleLevel := range roleLevels { + ids, err := g.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) + if err != nil { + return nil, err + } + userIDs = append(userIDs, ids...) + } + return g.GetGroupMembersInfo(ctx, groupID, userIDs) +} + +func (g *GroupCacheRedis) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (_ []*relationtb.GroupMemberModel, err error) { + if len(groupIDs) == 0 { + groupIDs, err = g.GetJoinedGroupIDs(ctx, userID) + if err != nil { + return nil, err + } + } + return batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string { + return g.getGroupMemberInfoKey(groupID, userID) + }, func(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { + return g.groupMemberDB.Take(ctx, groupID, userID) + }) +} diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index ccac88d68b..4bc2a046aa 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -38,7 +38,7 @@ const ( var errIndex = errors.New("err index") type metaCache interface { - ExecDel(ctx context.Context) error + ExecDel(ctx context.Context, distinct ...bool) error // delete key rapid DelKey(ctx context.Context, key string) error AddKeys(keys ...string) @@ -57,7 +57,10 @@ type metaCacheRedis struct { retryInterval time.Duration } -func (m *metaCacheRedis) ExecDel(ctx context.Context) error { +func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error { + if len(distinct) > 0 && distinct[0] { + m.keys = utils.Distinct(m.keys) + } if len(m.keys) > 0 { log.ZDebug(ctx, "delete cache", "keys", m.keys) for _, key := range m.keys { diff --git a/pkg/common/db/cache/msg.go b/pkg/common/db/cache/msg.go index f86b44d9b7..5cd3cb22c5 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 { @@ -314,7 +287,7 @@ func (c *msgCache) GetTokensWithoutError(ctx context.Context, userID string, pla func (c *msgCache) SetTokenMapByUidPid(ctx context.Context, userID string, platform int, m map[string]int) error { key := uidPidToken + userID + ":" + constant.PlatformIDToName(platform) - mm := make(map[string]interface{}) + mm := make(map[string]any) for k, v := range m { mm[k] = v } @@ -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 a5be018eda..3fddf59650 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/s3.go b/pkg/common/db/cache/s3.go index 3520ba2ec7..ba40ceaccc 100644 --- a/pkg/common/db/cache/s3.go +++ b/pkg/common/db/cache/s3.go @@ -14,8 +14,8 @@ import ( type ObjectCache interface { metaCache - GetName(ctx context.Context, name string) (*relationtb.ObjectModel, error) - DelObjectName(names ...string) ObjectCache + GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error) + DelObjectName(engine string, names ...string) ObjectCache } func NewObjectCacheRedis(rdb redis.UniversalClient, objDB relationtb.ObjectInfoModelInterface) ObjectCache { @@ -44,23 +44,23 @@ func (g *objectCacheRedis) NewCache() ObjectCache { } } -func (g *objectCacheRedis) DelObjectName(names ...string) ObjectCache { +func (g *objectCacheRedis) DelObjectName(engine string, names ...string) ObjectCache { objectCache := g.NewCache() keys := make([]string, 0, len(names)) for _, name := range names { - keys = append(keys, g.getObjectKey(name)) + keys = append(keys, g.getObjectKey(name, engine)) } objectCache.AddKeys(keys...) return objectCache } -func (g *objectCacheRedis) getObjectKey(name string) string { - return "OBJECT:" + name +func (g *objectCacheRedis) getObjectKey(engine string, name string) string { + return "OBJECT:" + engine + ":" + name } -func (g *objectCacheRedis) GetName(ctx context.Context, name string) (*relationtb.ObjectModel, error) { - return getCache(ctx, g.rcClient, g.getObjectKey(name), g.expireTime, func(ctx context.Context) (*relationtb.ObjectModel, error) { - return g.objDB.Take(ctx, name) +func (g *objectCacheRedis) GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error) { + return getCache(ctx, g.rcClient, g.getObjectKey(name, engine), g.expireTime, func(ctx context.Context) (*relationtb.ObjectModel, error) { + return g.objDB.Take(ctx, engine, name) }) } diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index d1164f2c08..979bd06e4c 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -22,6 +22,8 @@ import ( "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" @@ -31,8 +33,6 @@ import ( "github.com/dtm-labs/rockscache" "github.com/redis/go-redis/v9" - - relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) const ( @@ -59,7 +59,8 @@ type UserCache interface { type UserCacheRedis struct { metaCache - rdb redis.UniversalClient + rdb redis.UniversalClient + //userDB relationtb.UserModelInterface userDB relationtb.UserModelInterface expireTime time.Duration rcClient *rockscache.Client @@ -100,39 +101,13 @@ func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string { } func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) { - return getCache( - ctx, - u.rcClient, - u.getUserInfoKey(userID), - u.expireTime, - func(ctx context.Context) (*relationtb.UserModel, error) { - return u.userDB.Take(ctx, userID) - }, + return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) { + return u.userDB.Take(ctx, userID) + }, ) } func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) { - //var keys []string - //for _, userID := range userIDs { - // keys = append(keys, u.getUserInfoKey(userID)) - //} - //return batchGetCache( - // ctx, - // u.rcClient, - // keys, - // u.expireTime, - // func(user *relationtb.UserModel, keys []string) (int, error) { - // for i, key := range keys { - // if key == u.getUserInfoKey(user.UserID) { - // return i, nil - // } - // } - // return 0, errIndex - // }, - // func(ctx context.Context) ([]*relationtb.UserModel, error) { - // return u.userDB.Find(ctx, userIDs) - // }, - //) return batchGetCache2(ctx, u.rcClient, u.expireTime, userIDs, func(userID string) string { return u.getUserInfoKey(userID) }, func(ctx context.Context, userID string) (*relationtb.UserModel, error) { @@ -214,8 +189,7 @@ func (u *UserCacheRedis) SetUserStatus(ctx context.Context, userID string, statu UserIDNum := crc32.ChecksumIEEE([]byte(userID)) modKey := strconv.Itoa(int(UserIDNum % statusMod)) key := olineStatusKey + modKey - log.ZDebug(ctx, "SetUserStatus args", "userID", userID, "status", status, - "platformID", platformID, "modKey", modKey, "key", key) + log.ZDebug(ctx, "SetUserStatus args", "userID", userID, "status", status, "platformID", platformID, "modKey", modKey, "key", key) isNewKey, err := u.rdb.Exists(ctx, key).Result() if err != nil { return errs.Wrap(err) diff --git a/pkg/common/db/controller/black.go b/pkg/common/db/controller/black.go index 70e942a779..e68d06b01e 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 def4902651..0000000000 --- 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 0aaa95880c..2a0cb63e46 100644 --- a/pkg/common/db/controller/conversation.go +++ b/pkg/common/db/controller/conversation.go @@ -18,6 +18,8 @@ import ( "context" "time" + "github.com/OpenIMSDK/tools/pagination" + "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/OpenIMSDK/protocol/constant" @@ -31,7 +33,7 @@ import ( type ConversationDatabase interface { // UpdateUserConversationFiled 更新用户该会话的属性信息 - UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) error + UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error // CreateConversation 创建一批新的会话 CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error // SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作 @@ -39,26 +41,26 @@ type ConversationDatabase interface { // FindConversations 根据会话ID获取某个用户的多个会话 FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) // FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID - FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) + //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) // GetUserAllConversation 获取一个用户在服务器上所有的会话 GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) // SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性 SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error // SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作 - SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]interface{}) error + SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) error CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error GetConversationIDs(ctx context.Context, userID string) ([]string, error) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) GetAllConversationIDs(ctx context.Context) ([]string, error) GetAllConversationIDsNumber(ctx context.Context) (int64, error) - PageConversationIDs(ctx context.Context, pageNumber, showNumber int32) (conversationIDs []string, err error) + PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) } -func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase { +func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase { return &conversationDatabase{ conversationDB: conversation, cache: cache, @@ -69,22 +71,21 @@ func NewConversationDatabase(conversation relationtb.ConversationModelInterface, type conversationDatabase struct { conversationDB relationtb.ConversationModelInterface cache cache.ConversationCache - tx tx.Tx + tx tx.CtxTx } -func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]interface{}) (err error) { - cache := c.cache.NewCache() - if conversation.GroupID != "" { - cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(conversation.GroupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(conversation.GroupID) - } - if err := c.tx.Transaction(func(tx any) error { - conversationTx := c.conversationDB.NewTx(tx) - haveUserIDs, err := conversationTx.FindUserID(ctx, userIDs, []string{conversation.ConversationID}) +func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) (err error) { + return c.tx.Transaction(ctx, func(ctx context.Context) error { + cache := c.cache.NewCache() + if conversation.GroupID != "" { + cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(conversation.GroupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(conversation.GroupID) + } + haveUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversation.ConversationID}) if err != nil { return err } if len(haveUserIDs) > 0 { - _, err = conversationTx.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap) + _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap) if err != nil { return err } @@ -112,20 +113,17 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, conversations = append(conversations, temp) } if len(conversations) > 0 { - err = conversationTx.Create(ctx, conversations) + err = c.conversationDB.Create(ctx, conversations) if err != nil { return err } cache = cache.DelConversationIDs(NotUserIDs...).DelUserConversationIDsHash(NotUserIDs...).DelConversations(conversation.ConversationID, NotUserIDs...) } - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return cache.ExecDel(ctx) + }) } -func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) error { +func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error { _, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args) if err != nil { return err @@ -153,19 +151,18 @@ func (c *conversationDatabase) CreateConversation(ctx context.Context, conversat } func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Context, conversations []*relationtb.ConversationModel) error { - cache := c.cache.NewCache() - if err := c.tx.Transaction(func(tx any) error { - conversationTx := c.conversationDB.NewTx(tx) + return c.tx.Transaction(ctx, func(ctx context.Context) error { + cache := c.cache.NewCache() for _, conversation := range conversations { for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} { ownerUserID := v[0] userID := v[1] - haveUserIDs, err := conversationTx.FindUserID(ctx, []string{ownerUserID}, []string{conversation.ConversationID}) + haveUserIDs, err := c.conversationDB.FindUserID(ctx, []string{ownerUserID}, []string{conversation.ConversationID}) if err != nil { return err } if len(haveUserIDs) > 0 { - _, err := conversationTx.UpdateByMap(ctx, []string{ownerUserID}, conversation.ConversationID, map[string]interface{}{"is_private_chat": conversation.IsPrivateChat}) + _, err := c.conversationDB.UpdateByMap(ctx, []string{ownerUserID}, conversation.ConversationID, map[string]any{"is_private_chat": conversation.IsPrivateChat}) if err != nil { return err } @@ -176,18 +173,15 @@ func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Con newConversation.UserID = userID newConversation.ConversationID = conversation.ConversationID newConversation.IsPrivateChat = conversation.IsPrivateChat - if err := conversationTx.Create(ctx, []*relationtb.ConversationModel{&newConversation}); err != nil { + if err := c.conversationDB.Create(ctx, []*relationtb.ConversationModel{&newConversation}); err != nil { return err } cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID) } } } - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return cache.ExecDel(ctx) + }) } func (c *conversationDatabase) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { @@ -203,28 +197,26 @@ func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, owner } func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error { - cache := c.cache.NewCache() - - groupIDs := utils.Distinct(utils.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) { - return e.GroupID, e.GroupID != "" - })) - for _, groupID := range groupIDs { - cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(groupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID) - } - if err := c.tx.Transaction(func(tx any) error { + return c.tx.Transaction(ctx, func(ctx context.Context) error { + cache := c.cache.NewCache() + groupIDs := utils.Distinct(utils.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) { + return e.GroupID, e.GroupID != "" + })) + for _, groupID := range groupIDs { + cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(groupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID) + } var conversationIDs []string for _, conversation := range conversations { conversationIDs = append(conversationIDs, conversation.ConversationID) cache = cache.DelConversations(conversation.OwnerUserID, conversation.ConversationID) } - conversationTx := c.conversationDB.NewTx(tx) - existConversations, err := conversationTx.Find(ctx, ownerUserID, conversationIDs) + existConversations, err := c.conversationDB.Find(ctx, ownerUserID, conversationIDs) if err != nil { return err } if len(existConversations) > 0 { for _, conversation := range conversations { - err = conversationTx.Update(ctx, conversation) + err = c.conversationDB.Update(ctx, conversation) if err != nil { return err } @@ -246,23 +238,22 @@ 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 nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return cache.ExecDel(ctx) + }) } -func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { - return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) -} +//func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { +// return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) +//} func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error { - cache := c.cache.NewCache() - conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) - if err := c.tx.Transaction(func(tx any) error { + return c.tx.Transaction(ctx, func(ctx context.Context) error { + cache := c.cache.NewCache() + conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID}) if err != nil { return err @@ -281,18 +272,15 @@ func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, return err } } - _, err = c.conversationDB.UpdateByMap(ctx, existConversationUserIDs, conversationID, map[string]interface{}{"max_seq": 0}) + _, err = c.conversationDB.UpdateByMap(ctx, existConversationUserIDs, conversationID, map[string]any{"max_seq": 0}) if err != nil { return err } for _, v := range existConversationUserIDs { cache = cache.DelConversations(v, conversationID) } - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return c.cache.ExecDel(ctx) + }) } func (c *conversationDatabase) GetConversationIDs(ctx context.Context, userID string) ([]string, error) { @@ -311,14 +299,10 @@ func (c *conversationDatabase) GetAllConversationIDsNumber(ctx context.Context) return c.conversationDB.GetAllConversationIDsNumber(ctx) } -func (c *conversationDatabase) PageConversationIDs(ctx context.Context, pageNumber, showNumber int32) ([]string, error) { - return c.conversationDB.PageConversationIDs(ctx, pageNumber, showNumber) +func (c *conversationDatabase) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) ([]string, error) { + return c.conversationDB.PageConversationIDs(ctx, pagination) } -//func (c *conversationDatabase) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) { -// return c.cache.GetUserAllHasReadSeqs(ctx, ownerUserID) -//} - func (c *conversationDatabase) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) { return c.conversationDB.GetConversationsByConversationID(ctx, conversationIDs) } diff --git a/pkg/common/db/controller/friend.go b/pkg/common/db/controller/friend.go index 7816ef9350..29b2ef9b1f 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 { - m := make(map[string]interface{}, 1) +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 194f3e8b20..4147d59c09 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -16,23 +16,18 @@ package controller import ( "context" - "fmt" "time" + "github.com/OpenIMSDK/tools/pagination" "github.com/dtm-labs/rockscache" - "github.com/redis/go-redis/v9" - "go.mongodb.org/mongo-driver/mongo" - "gorm.io/gorm" "github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/utils" + "github.com/redis/go-redis/v9" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" - unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" ) type GroupDatabase interface { @@ -40,23 +35,26 @@ type GroupDatabase interface { CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) - FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) - SearchGroup(ctx context.Context, keyword string, pageNumber, showNumber int32) (uint32, []*relationtb.GroupModel, error) + SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) UpdateGroup(ctx context.Context, groupID string, data map[string]any) error DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // 解散群,并删除群成员 - GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) - // GroupMember + TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) - FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) + FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) // * + FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) // * + FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) // * + FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) // * + FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) - PageGroupRequest(ctx context.Context, groupIDs []string, pageNumber, showNumber int32) (uint32, []*relationtb.GroupRequestModel, error) + PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) + GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) - PageGetJoinGroup(ctx context.Context, userID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) - PageGetGroupMember(ctx context.Context, groupID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) - SearchGroupMember(ctx context.Context, keyword string, groupIDs []string, userIDs []string, roleLevels []int32, pageNumber, showNumber int32) (uint32, []*relationtb.GroupMemberModel, error) + PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) + SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) @@ -67,15 +65,8 @@ type GroupDatabase interface { // GroupRequest CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationtb.GroupRequestModel, error) - FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*relationtb.GroupRequestModel, error) - PageGroupRequestUser(ctx context.Context, userID string, pageNumber, showNumber int32) (uint32, []*relationtb.GroupRequestModel, error) - // SuperGroupModelInterface - FindSuperGroup(ctx context.Context, groupIDs []string) ([]*unrelationtb.SuperGroupModel, error) - FindJoinSuperGroup(ctx context.Context, userID string) ([]string, error) - CreateSuperGroup(ctx context.Context, groupID string, initMemberIDList []string) error - DeleteSuperGroup(ctx context.Context, groupID string) error - DeleteSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error - CreateSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error + FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error) + PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) // 获取群总数 CountTotal(ctx context.Context, before *time.Time) (count int64, err error) @@ -85,126 +76,115 @@ type GroupDatabase interface { } func NewGroupDatabase( - group relationtb.GroupModelInterface, - member relationtb.GroupMemberModelInterface, - request relationtb.GroupRequestModelInterface, - tx tx.Tx, + rdb redis.UniversalClient, + groupDB relationtb.GroupModelInterface, + groupMemberDB relationtb.GroupMemberModelInterface, + groupRequestDB relationtb.GroupRequestModelInterface, ctxTx tx.CtxTx, - superGroup unrelationtb.SuperGroupModelInterface, - cache cache.GroupCache, + groupHash cache.GroupHash, ) GroupDatabase { - database := &groupDatabase{ - groupDB: group, - groupMemberDB: member, - groupRequestDB: request, - tx: tx, - ctxTx: ctxTx, - cache: cache, - mongoDB: superGroup, - } - return database -} - -func InitGroupDatabase(db *gorm.DB, rdb redis.UniversalClient, database *mongo.Database, hashCode func(ctx context.Context, groupID string) (uint64, error)) GroupDatabase { rcOptions := rockscache.NewDefaultOptions() rcOptions.StrongConsistency = true rcOptions.RandomExpireAdjustment = 0.2 - return NewGroupDatabase( - relation.NewGroupDB(db), - relation.NewGroupMemberDB(db), - relation.NewGroupRequest(db), - tx.NewGorm(db), - tx.NewMongo(database.Client()), - unrelation.NewSuperGroupMongoDriver(database), - cache.NewGroupCacheRedis( - rdb, - relation.NewGroupDB(db), - relation.NewGroupMemberDB(db), - relation.NewGroupRequest(db), - unrelation.NewSuperGroupMongoDriver(database), - hashCode, - rcOptions, - ), - ) + return &groupDatabase{ + groupDB: groupDB, + groupMemberDB: groupMemberDB, + groupRequestDB: groupRequestDB, + ctxTx: ctxTx, + cache: cache.NewGroupCacheRedis(rdb, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions), + } } type groupDatabase struct { groupDB relationtb.GroupModelInterface groupMemberDB relationtb.GroupMemberModelInterface groupRequestDB relationtb.GroupRequestModelInterface - tx tx.Tx ctxTx tx.CtxTx cache cache.GroupCache - mongoDB unrelationtb.SuperGroupModelInterface } -func (g *groupDatabase) GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) { - return g.groupDB.GetGroupIDsByGroupType(ctx, groupType) +func (g *groupDatabase) FindGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupMemberModel, error) { + return g.cache.GetGroupMembersInfo(ctx, groupID, userIDs) } -func (g *groupDatabase) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) { - return g.cache.GetGroupMemberIDs(ctx, groupID) +func (g *groupDatabase) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*relationtb.GroupMemberModel, error) { + return g.cache.FindGroupMemberUser(ctx, groupIDs, userID) } -func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) { - num, err := g.cache.GetGroupMemberNum(ctx, groupID) - if err != nil { - return 0, err - } - return uint32(num), nil +func (g *groupDatabase) FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { + return g.cache.GetGroupRolesLevelMemberInfo(ctx, groupID, roleLevels) } -func (g *groupDatabase) CreateGroup( - ctx context.Context, - groups []*relationtb.GroupModel, - groupMembers []*relationtb.GroupMemberModel, -) error { - cache := g.cache.NewCache() - if err := g.tx.Transaction(func(tx any) error { +func (g *groupDatabase) FindGroupMemberAll(ctx context.Context, groupID string) ([]*relationtb.GroupMemberModel, error) { + return g.cache.GetAllGroupMembersInfo(ctx, groupID) +} + +func (g *groupDatabase) FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error) { + return g.cache.GetGroupsOwner(ctx, groupIDs) +} + +func (g *groupDatabase) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) { + return g.cache.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) +} + +func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error { + if len(groups)+len(groupMembers) == 0 { + return nil + } + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + c := g.cache.NewCache() if len(groups) > 0 { - if err := g.groupDB.NewTx(tx).Create(ctx, groups); err != nil { + if err := g.groupDB.Create(ctx, groups); err != nil { return err } + for _, group := range groups { + c = c.DelGroupsInfo(group.GroupID). + DelGroupMembersHash(group.GroupID). + DelGroupMembersHash(group.GroupID). + DelGroupsMemberNum(group.GroupID). + DelGroupMemberIDs(group.GroupID). + DelGroupAllRoleLevel(group.GroupID) + } } if len(groupMembers) > 0 { - if err := g.groupMemberDB.NewTx(tx).Create(ctx, groupMembers); err != nil { + if err := g.groupMemberDB.Create(ctx, groupMembers); err != nil { return err } - } - createGroupIDs := utils.DistinctAnyGetComparable(groups, func(group *relationtb.GroupModel) string { - return group.GroupID - }) - m := make(map[string]struct{}) - - for _, groupMember := range groupMembers { - if _, ok := m[groupMember.GroupID]; !ok { - m[groupMember.GroupID] = struct{}{} - cache = cache.DelGroupMemberIDs(groupMember.GroupID).DelGroupMembersHash(groupMember.GroupID).DelGroupsMemberNum(groupMember.GroupID) + for _, groupMember := range groupMembers { + c = c.DelGroupMembersHash(groupMember.GroupID). + DelGroupsMemberNum(groupMember.GroupID). + DelGroupMemberIDs(groupMember.GroupID). + DelJoinedGroupID(groupMember.UserID). + DelGroupMembersInfo(groupMember.GroupID, groupMember.UserID). + DelGroupAllRoleLevel(groupMember.GroupID) } - cache = cache.DelJoinedGroupID(groupMember.UserID).DelGroupMembersInfo(groupMember.GroupID, groupMember.UserID) } - cache = cache.DelGroupsInfo(createGroupIDs...) - return nil - }); err != nil { - return err + return c.ExecDel(ctx, true) + }) +} + +func (g *groupDatabase) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) { + return g.cache.GetGroupMemberIDs(ctx, groupID) +} + +func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) { + num, err := g.cache.GetGroupMemberNum(ctx, groupID) + if err != nil { + return 0, err } - return cache.ExecDel(ctx) + return uint32(num), nil } -func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) { +func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (*relationtb.GroupModel, error) { return g.cache.GetGroupInfo(ctx, groupID) } -func (g *groupDatabase) FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) { +func (g *groupDatabase) FindGroup(ctx context.Context, groupIDs []string) ([]*relationtb.GroupModel, error) { return g.cache.GetGroupsInfo(ctx, groupIDs) } -func (g *groupDatabase) SearchGroup( - ctx context.Context, - keyword string, - pageNumber, showNumber int32, -) (uint32, []*relationtb.GroupModel, error) { - return g.groupDB.Search(ctx, keyword, pageNumber, showNumber) +func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) { + return g.groupDB.Search(ctx, keyword, pagination) } func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data map[string]any) error { @@ -215,166 +195,97 @@ func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data ma } func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error { - cache := g.cache.NewCache() - if err := g.tx.Transaction(func(tx any) error { - if err := g.groupDB.NewTx(tx).UpdateStatus(ctx, groupID, constant.GroupStatusDismissed); err != nil { + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + c := g.cache.NewCache() + if err := g.groupDB.UpdateState(ctx, groupID, constant.GroupStatusDismissed); err != nil { return err } if deleteMember { - if err := g.groupMemberDB.NewTx(tx).DeleteGroup(ctx, []string{groupID}); err != nil { - return err - } userIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID) if err != nil { return err } - cache = cache.DelJoinedGroupID(userIDs...).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelGroupMembersHash(groupID) + if err := g.groupMemberDB.Delete(ctx, groupID, nil); err != nil { + return err + } + c = c.DelJoinedGroupID(userIDs...). + DelGroupMemberIDs(groupID). + DelGroupsMemberNum(groupID). + DelGroupMembersHash(groupID). + DelGroupAllRoleLevel(groupID). + DelGroupMembersInfo(groupID, userIDs...) } - cache = cache.DelGroupsInfo(groupID) - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return c.DelGroupsInfo(groupID).ExecDel(ctx) + }) } -func (g *groupDatabase) TakeGroupMember( - ctx context.Context, - groupID string, - userID string, -) (groupMember *relationtb.GroupMemberModel, err error) { +func (g *groupDatabase) TakeGroupMember(ctx context.Context, groupID string, userID string) (*relationtb.GroupMemberModel, error) { return g.cache.GetGroupMemberInfo(ctx, groupID, userID) } func (g *groupDatabase) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { - return g.groupMemberDB.TakeOwner(ctx, groupID) // todo cache group owner + return g.cache.GetGroupOwner(ctx, groupID) } func (g *groupDatabase) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { return g.groupMemberDB.FindUserManagedGroupID(ctx, userID) } -func (g *groupDatabase) PageGroupRequest( - ctx context.Context, - groupIDs []string, - pageNumber, showNumber int32, -) (uint32, []*relationtb.GroupRequestModel, error) { - return g.groupRequestDB.PageGroup(ctx, groupIDs, pageNumber, showNumber) -} - -func (g *groupDatabase) FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (totalGroupMembers []*relationtb.GroupMemberModel, err error) { - if len(groupIDs) == 0 && len(roleLevels) == 0 && len(userIDs) == 1 { - gIDs, err := g.cache.GetJoinedGroupIDs(ctx, userIDs[0]) - if err != nil { - return nil, err - } - var res []*relationtb.GroupMemberModel - for _, groupID := range gIDs { - v, err := g.cache.GetGroupMemberInfo(ctx, groupID, userIDs[0]) - if err != nil { - return nil, err - } - res = append(res, v) - } - return res, nil - } - if len(roleLevels) == 0 { - for _, groupID := range groupIDs { - groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, userIDs) - if err != nil { - return nil, err - } - totalGroupMembers = append(totalGroupMembers, groupMembers...) - } - return totalGroupMembers, nil - } - return g.groupMemberDB.Find(ctx, groupIDs, userIDs, roleLevels) +func (g *groupDatabase) PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) { + return g.groupRequestDB.PageGroup(ctx, groupIDs, pagination) } -func (g *groupDatabase) PageGetJoinGroup( - ctx context.Context, - userID string, - pageNumber, showNumber int32, -) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) { +func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) { groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID) if err != nil { return 0, nil, err } - for _, groupID := range utils.Paginate(groupIDs, int(pageNumber), int(showNumber)) { + for _, groupID := range utils.Paginate(groupIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) { groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, []string{userID}) if err != nil { return 0, nil, err } totalGroupMembers = append(totalGroupMembers, groupMembers...) } - return uint32(len(groupIDs)), totalGroupMembers, nil + return int64(len(groupIDs)), totalGroupMembers, nil } -func (g *groupDatabase) PageGetGroupMember( - ctx context.Context, - groupID string, - pageNumber, showNumber int32, -) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) { +func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) { groupMemberIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID) if err != nil { return 0, nil, err } - pageIDs := utils.Paginate(groupMemberIDs, int(pageNumber), int(showNumber)) + pageIDs := utils.Paginate(groupMemberIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) if len(pageIDs) == 0 { - return uint32(len(groupMemberIDs)), nil, nil + return int64(len(groupMemberIDs)), nil, nil } members, err := g.cache.GetGroupMembersInfo(ctx, groupID, pageIDs) if err != nil { return 0, nil, err } - return uint32(len(groupMemberIDs)), members, nil + return int64(len(groupMemberIDs)), members, nil } -func (g *groupDatabase) SearchGroupMember( - ctx context.Context, - keyword string, - groupIDs []string, - userIDs []string, - roleLevels []int32, - pageNumber, showNumber int32, -) (uint32, []*relationtb.GroupMemberModel, error) { - return g.groupMemberDB.SearchMember(ctx, keyword, groupIDs, userIDs, roleLevels, pageNumber, showNumber) +func (g *groupDatabase) SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) { + return g.groupMemberDB.SearchMember(ctx, keyword, groupID, pagination) } -func (g *groupDatabase) HandlerGroupRequest( - ctx context.Context, - groupID string, - userID string, - handledMsg string, - handleResult int32, - member *relationtb.GroupMemberModel, -) error { - //cache := g.cache.NewCache() - //if err := g.tx.Transaction(func(tx any) error { - // if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil { - // return err - // } - // if member != nil { - // if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationtb.GroupMemberModel{member}); err != nil { - // return err - // } - // cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID) - // } - // return nil - //}); err != nil { - // return err - //} - //return cache.ExecDel(ctx) - - return g.tx.Transaction(func(tx any) error { - if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil { +func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error { + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + if err := g.groupRequestDB.UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil { return err } if member != nil { - if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationtb.GroupMemberModel{member}); err != nil { + if err := g.groupMemberDB.Create(ctx, []*relationtb.GroupMemberModel{member}); err != nil { return err } - if err := g.cache.NewCache().DelGroupMembersHash(groupID).DelGroupMembersInfo(groupID, member.UserID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID).ExecDel(ctx); err != nil { + c := g.cache.DelGroupMembersHash(groupID). + DelGroupMembersInfo(groupID, member.UserID). + DelGroupMemberIDs(groupID). + DelGroupsMemberNum(groupID). + DelJoinedGroupID(member.UserID). + DelGroupRoleLevel(groupID, []int32{member.RoleLevel}) + if err := c.ExecDel(ctx); err != nil { return err } } @@ -391,13 +302,11 @@ func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, u DelGroupsMemberNum(groupID). DelJoinedGroupID(userIDs...). DelGroupMembersInfo(groupID, userIDs...). + DelGroupAllRoleLevel(groupID). ExecDel(ctx) } -func (g *groupDatabase) MapGroupMemberUserID( - ctx context.Context, - groupIDs []string, -) (map[string]*relationtb.GroupSimpleUserID, error) { +func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) { return g.cache.GetGroupMemberHashMap(ctx, groupIDs) } @@ -414,62 +323,54 @@ func (g *groupDatabase) MapGroupMemberNum(ctx context.Context, groupIDs []string } func (g *groupDatabase) TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error { - return g.tx.Transaction(func(tx any) error { - rowsAffected, err := g.groupMemberDB.NewTx(tx).UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel) - if err != nil { + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel); err != nil { return err } - if rowsAffected != 1 { - return utils.Wrap(fmt.Errorf("oldOwnerUserID %s rowsAffected = %d", oldOwnerUserID, rowsAffected), "") - } - rowsAffected, err = g.groupMemberDB.NewTx(tx).UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner) - if err != nil { + if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner); err != nil { return err } - if rowsAffected != 1 { - return utils.Wrap(fmt.Errorf("newOwnerUserID %s rowsAffected = %d", newOwnerUserID, rowsAffected), "") - } - return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID).DelGroupMembersHash(groupID).ExecDel(ctx) + return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID). + DelGroupAllRoleLevel(groupID). + DelGroupMembersHash(groupID).ExecDel(ctx) }) } -func (g *groupDatabase) UpdateGroupMember( - ctx context.Context, - groupID string, - userID string, - data map[string]any, -) error { +func (g *groupDatabase) UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error { if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil { return err } - return g.cache.DelGroupMembersInfo(groupID, userID).ExecDel(ctx) + c := g.cache.DelGroupMembersInfo(groupID, userID) + if g.groupMemberDB.IsUpdateRoleLevel(data) { + c = c.DelGroupAllRoleLevel(groupID) + } + return c.ExecDel(ctx) } func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error { - cache := g.cache.NewCache() - if err := g.tx.Transaction(func(tx any) error { + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { + c := g.cache.NewCache() for _, item := range data { - if err := g.groupMemberDB.NewTx(tx).Update(ctx, item.GroupID, item.UserID, item.Map); err != nil { + if err := g.groupMemberDB.Update(ctx, item.GroupID, item.UserID, item.Map); err != nil { return err } - cache = cache.DelGroupMembersInfo(item.GroupID, item.UserID) + if g.groupMemberDB.IsUpdateRoleLevel(item.Map) { + c = c.DelGroupAllRoleLevel(item.GroupID) + } + c = c.DelGroupMembersInfo(item.GroupID, item.UserID).DelGroupMembersHash(item.GroupID) } - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) + return c.ExecDel(ctx, true) + }) } func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error { - return g.tx.Transaction(func(tx any) error { - db := g.groupRequestDB.NewTx(tx) + return g.ctxTx.Transaction(ctx, func(ctx context.Context) error { for _, request := range requests { - if err := db.Delete(ctx, request.GroupID, request.UserID); err != nil { + if err := g.groupRequestDB.Delete(ctx, request.GroupID, request.UserID); err != nil { return err } } - return db.Create(ctx, requests) + return g.groupRequestDB.Create(ctx, requests) }) } @@ -481,65 +382,8 @@ func (g *groupDatabase) TakeGroupRequest( return g.groupRequestDB.Take(ctx, groupID, userID) } -func (g *groupDatabase) PageGroupRequestUser( - ctx context.Context, - userID string, - pageNumber, showNumber int32, -) (uint32, []*relationtb.GroupRequestModel, error) { - return g.groupRequestDB.Page(ctx, userID, pageNumber, showNumber) -} - -func (g *groupDatabase) FindSuperGroup( - ctx context.Context, - groupIDs []string, -) (models []*unrelationtb.SuperGroupModel, err error) { - return g.cache.GetSuperGroupMemberIDs(ctx, groupIDs...) -} - -func (g *groupDatabase) FindJoinSuperGroup(ctx context.Context, userID string) ([]string, error) { - return g.cache.GetJoinedSuperGroupIDs(ctx, userID) -} - -func (g *groupDatabase) CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error { - if err := g.mongoDB.CreateSuperGroup(ctx, groupID, initMemberIDs); err != nil { - return err - } - return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(initMemberIDs...).ExecDel(ctx) -} - -func (g *groupDatabase) DeleteSuperGroup(ctx context.Context, groupID string) error { - cache := g.cache.NewCache() - if err := g.ctxTx.Transaction(ctx, func(ctx context.Context) error { - if err := g.mongoDB.DeleteSuperGroup(ctx, groupID); err != nil { - return err - } - models, err := g.cache.GetSuperGroupMemberIDs(ctx, groupID) - if err != nil { - return err - } - cache = cache.DelSuperGroupMemberIDs(groupID) - if len(models) > 0 { - cache = cache.DelJoinedSuperGroupIDs(models[0].MemberIDs...) - } - return nil - }); err != nil { - return err - } - return cache.ExecDel(ctx) -} - -func (g *groupDatabase) DeleteSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error { - if err := g.mongoDB.RemoverUserFromSuperGroup(ctx, groupID, userIDs); err != nil { - return err - } - return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(userIDs...).ExecDel(ctx) -} - -func (g *groupDatabase) CreateSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error { - if err := g.mongoDB.AddUserToSuperGroup(ctx, groupID, userIDs); err != nil { - return err - } - return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(userIDs...).ExecDel(ctx) +func (g *groupDatabase) PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) { + return g.groupRequestDB.Page(ctx, userID, pagination) } func (g *groupDatabase) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { @@ -550,14 +394,10 @@ func (g *groupDatabase) CountRangeEverydayTotal(ctx context.Context, start time. return g.groupDB.CountRangeEverydayTotal(ctx, start, end) } -func (g *groupDatabase) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*relationtb.GroupRequestModel, error) { +func (g *groupDatabase) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error) { return g.groupRequestDB.FindGroupRequests(ctx, groupID, userIDs) } -func (g *groupDatabase) FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) { - return g.groupDB.FindNotDismissedGroup(ctx, groupIDs) -} - func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error { if len(groupIDs) == 0 { return nil @@ -566,6 +406,5 @@ func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []st for _, groupID := range groupIDs { c = c.DelGroupMembersHash(groupID) } - return c.ExecDel(ctx) } diff --git a/pkg/common/db/controller/msg.go b/pkg/common/db/controller/msg.go index cba0a6bbd9..fb0a9c702f 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/msg_test.go b/pkg/common/db/controller/msg_test.go index ba5aecd258..cfb969b3e6 100644 --- a/pkg/common/db/controller/msg_test.go +++ b/pkg/common/db/controller/msg_test.go @@ -235,7 +235,7 @@ func Test_FindBySeq(t *testing.T) { func TestName(t *testing.T) { db := GetDB() var seqs []int64 - for i := int64(1); i <= 4; i++ { + for i := int64(1); i <= 50; i++ { seqs = append(seqs, i) } msgs, err := db.getMsgBySeqsRange(context.Background(), "4931176757", "si_3866692501_4931176757", seqs, seqs[0], seqs[len(seqs)-1]) diff --git a/pkg/common/db/controller/s3.go b/pkg/common/db/controller/s3.go index ddbd5d27f4..6916a7d30d 100644 --- a/pkg/common/db/controller/s3.go +++ b/pkg/common/db/controller/s3.go @@ -72,14 +72,15 @@ func (s *s3Database) CompleteMultipartUpload(ctx context.Context, uploadID strin } func (s *s3Database) SetObject(ctx context.Context, info *relation.ObjectModel) error { + info.Engine = s.s3.Engine() if err := s.db.SetObject(ctx, info); err != nil { return err } - return s.cache.DelObjectName(info.Name).ExecDel(ctx) + return s.cache.DelObjectName(info.Engine, info.Name).ExecDel(ctx) } func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error) { - obj, err := s.cache.GetName(ctx, name) + obj, err := s.cache.GetName(ctx, s.s3.Engine(), name) if err != nil { return time.Time{}, "", err } diff --git a/pkg/common/db/controller/third.go b/pkg/common/db/controller/third.go index 971719b1f6..fb5b0ccbe7 100644 --- a/pkg/common/db/controller/third.go +++ b/pkg/common/db/controller/third.go @@ -18,10 +18,9 @@ import ( "context" "time" - "gorm.io/gorm" + "github.com/OpenIMSDK/tools/pagination" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - dbimpl "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" ) @@ -29,22 +28,15 @@ 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, pageNumber int32, showNumber int32) (uint32, []*relation.Log, error) - GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.Log, error) - FindUsers(ctx context.Context, userIDs []string) ([]*relation.UserModel, 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 { - cache cache.MsgModel - logdb relation.LogInterface - userdb relation.UserModelInterface -} - -// FindUsers implements ThirdDatabase. -func (t *thirdDatabase) FindUsers(ctx context.Context, userIDs []string) ([]*relation.UserModel, error) { - return t.userdb.Find(ctx, userIDs) + cache cache.MsgModel + logdb relation.LogInterface } // DeleteLogs implements ThirdDatabase. @@ -53,22 +45,22 @@ 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, pageNumber int32, showNumber int32) (uint32, []*relation.Log, error) { - return t.logdb.Search(ctx, keyword, start, end, pageNumber, showNumber) +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) } -func NewThirdDatabase(cache cache.MsgModel, db *gorm.DB) ThirdDatabase { - return &thirdDatabase{cache: cache, logdb: dbimpl.NewLogGorm(db), userdb: dbimpl.NewUserGorm(db)} +func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDatabase { + return &thirdDatabase{cache: cache, logdb: logdb} } func (t *thirdDatabase) FcmUpdateToken( diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 9c6fdc5c47..ca703b7290 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -18,16 +18,19 @@ 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/protocol/user" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "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/table/relation" ) type UserDatabase interface { @@ -38,15 +41,15 @@ type UserDatabase interface { // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db Create(ctx context.Context, users []*relation.UserModel) (err error) // Update update (non-zero value) external guarantee userID exists - Update(ctx context.Context, user *relation.UserModel) (err error) + //Update(ctx context.Context, user *relation.UserModel) (err error) // UpdateByMap update (zero value) external guarantee userID exists - UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) + UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) // Page If not found, no error is returned - Page(ctx context.Context, pageNumber, showNumber int32) (users []*relation.UserModel, count int64, err error) + Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) // IsExist true as long as one exists IsExist(ctx context.Context, userIDs []string) (exist bool, err error) // GetAllUserID Get all user IDs - GetAllUserID(ctx context.Context, pageNumber, showNumber int32) ([]string, error) + GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) // InitOnce Inside the function, first query whether it exists in the db, if it exists, do nothing; if it does not exist, insert it InitOnce(ctx context.Context, users []*relation.UserModel) (err error) // CountTotal Get the total number of users @@ -68,28 +71,40 @@ type UserDatabase interface { } type userDatabase struct { + tx tx.CtxTx userDB relation.UserModelInterface cache cache.UserCache - tx tx.Tx mongoDB unrelationtb.UserModelInterface } -func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx, mongoDB unrelationtb.UserModelInterface) UserDatabase { +func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.CtxTx, mongoDB unrelationtb.UserModelInterface) UserDatabase { return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB} } -func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) (err error) { +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 }) - result, err := u.userDB.Find(ctx, userIDs) + + // Find existing users in the database. + existingUsers, err := u.userDB.Find(ctx, userIDs) if err != nil { return err } - miss := utils.SliceAnySub(users, result, func(e *relation.UserModel) string { return e.UserID }) - if len(miss) > 0 { - _ = u.userDB.Create(ctx, miss) + + // 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 + } } + return nil } @@ -107,50 +122,42 @@ func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (use // Find Get the information of the specified user. If the userID is not found, no error will be returned. func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { - users, err = u.cache.GetUsersInfo(ctx, userIDs) - return + return u.cache.GetUsersInfo(ctx, userIDs) } // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db. func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) (err error) { - if err := u.tx.Transaction(func(tx any) error { - err = u.userDB.Create(ctx, users) - if err != nil { + return u.tx.Transaction(ctx, func(ctx context.Context) error { + if err = u.userDB.Create(ctx, users); err != nil { return err } - return nil - }); err != nil { - return err - } - var userIDs []string - for _, user := range users { - userIDs = append(userIDs, user.UserID) - } - return u.cache.DelUsersInfo(userIDs...).ExecDel(ctx) + return u.cache.DelUsersInfo(utils.Slice(users, func(e *relation.UserModel) string { + return e.UserID + })...).ExecDel(ctx) + }) } -// Update (non-zero value) externally guarantees that userID exists. -func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) { - if err := u.userDB.Update(ctx, user); err != nil { - return err - } - return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx) -} +//// Update (non-zero value) externally guarantees that userID exists. +//func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) { +// if err := u.userDB.Update(ctx, user); err != nil { +// return err +// } +// return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx) +//} // UpdateByMap update (zero value) externally guarantees that userID exists. -func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) { - if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil { - return err - } - return u.cache.DelUsersInfo(userID).ExecDel(ctx) +func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) { + return u.tx.Transaction(ctx, func(ctx context.Context) error { + if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil { + return err + } + return u.cache.DelUsersInfo(userID).ExecDel(ctx) + }) } // Page Gets, returns no error if not found. -func (u *userDatabase) Page( - ctx context.Context, - pageNumber, showNumber int32, -) (users []*relation.UserModel, count int64, err error) { - return u.userDB.Page(ctx, pageNumber, showNumber) +func (u *userDatabase) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) { + return u.userDB.Page(ctx, pagination) } // IsExist Does userIDs exist? As long as there is one, it will be true. @@ -166,8 +173,8 @@ func (u *userDatabase) IsExist(ctx context.Context, userIDs []string) (exist boo } // GetAllUserID Get all user IDs. -func (u *userDatabase) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) { - return u.userDB.GetAllUserID(ctx, pageNumber, showNumber) +func (u *userDatabase) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (total int64, userIDs []string, err error) { + return u.userDB.GetAllUserID(ctx, pagination) } // CountTotal Get the total number of users. diff --git a/pkg/common/db/mgo/black.go b/pkg/common/db/mgo/black.go new file mode 100644 index 0000000000..6235639aa9 --- /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/mgo/conversation.go b/pkg/common/db/mgo/conversation.go new file mode 100644 index 0000000000..72d04ebb3c --- /dev/null +++ b/pkg/common/db/mgo/conversation.go @@ -0,0 +1,150 @@ +package mgo + +import ( + "context" + "time" + + "github.com/OpenIMSDK/protocol/constant" + "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 NewConversationMongo(db *mongo.Database) (*ConversationMgo, error) { + 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 { + coll *mongo.Collection +} + +func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) { + return mgoutil.InsertMany(ctx, c.coll, conversations) +} + +func (c *ConversationMgo) Delete(ctx context.Context, groupIDs []string) (err error) { + 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 := 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 + } + return res.ModifiedCount, nil +} + +func (c *ConversationMgo) Update(ctx context.Context, conversation *relation.ConversationModel) (err error) { + 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 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 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 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 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 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 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 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 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 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 := mgoutil.Aggregate[int64](ctx, c.coll, []bson.M{ + {"$group": bson.M{"_id": "$conversation_id"}}, + {"$project": bson.M{"_id": 0, "conversation_id": "$_id"}}, + }) + if err != nil { + return 0, err + } + if len(counts) == 0 { + return 0, nil + } + return counts[0], nil +} + +func (c *ConversationMgo) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) { + 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 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 mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{ + "is_msg_destruct": 1, + "msg_destruct_time": bson.M{"$ne": 0}, + "$or": []bson.M{ + { + "$expr": bson.M{ + "$gt": []any{ + time.Now(), + bson.M{"$add": []any{"$msg_destruct_time", "$latest_msg_destruct_time"}}, + }, + }, + }, + { + "latest_msg_destruct_time": nil, + }, + }, + }) +} + +func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) { + 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/mgo/friend.go b/pkg/common/db/mgo/friend.go new file mode 100644 index 0000000000..aa9cb03011 --- /dev/null +++ b/pkg/common/db/mgo/friend.go @@ -0,0 +1,131 @@ +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" +) + +// FriendMgo implements FriendModelInterface using MongoDB as the storage backend. +type FriendMgo struct { + coll *mongo.Collection +} + +// NewFriendMongo creates a new instance of FriendMgo with the provided MongoDB database. +func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) { + 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 mgoutil.InsertMany(ctx, f.coll, friends) +} + +// Delete removes specified friends of the owner user. +func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) error { + filter := bson.M{ + "owner_user_id": ownerUserID, + "friend_user_id": bson.M{"$in": friendUserIDs}, + } + return mgoutil.DeleteOne(ctx, f.coll, filter) +} + +// UpdateByMap updates specific fields of a friend document using a map. +func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error { + if len(args) == 0 { + return nil + } + filter := bson.M{ + "owner_user_id": ownerUserID, + "friend_user_id": friendUserID, + } + return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true) +} + +// Update modifies multiple friend documents. +// func (f *FriendMgo) Update(ctx context.Context, friends []*relation.FriendModel) error { +// filter := bson.M{ +// "owner_user_id": ownerUserID, +// "friend_user_id": friendUserID, +// } +// return mgotool.UpdateMany(ctx, f.coll, filter, friends) +// } + +// UpdateRemark updates the remark for a specific friend. +func (f *FriendMgo) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error { + return f.UpdateByMap(ctx, ownerUserID, friendUserID, map[string]any{"remark": remark}) +} + +// Take retrieves a single friend document. Returns an error if not found. +func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string) (*relation.FriendModel, error) { + filter := bson.M{ + "owner_user_id": ownerUserID, + "friend_user_id": friendUserID, + } + return mgoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter) +} + +// FindUserState finds the friendship status between two users. +func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string) ([]*relation.FriendModel, error) { + filter := bson.M{ + "$or": []bson.M{ + {"owner_user_id": userID1, "friend_user_id": userID2}, + {"owner_user_id": userID2, "friend_user_id": userID1}, + }, + } + 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. +func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*relation.FriendModel, error) { + filter := bson.M{ + "owner_user_id": ownerUserID, + "friend_user_id": bson.M{"$in": friendUserIDs}, + } + return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter) +} + +// FindReversalFriends finds users who have added the specified user as a friend. +func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*relation.FriendModel, error) { + filter := bson.M{ + "owner_user_id": bson.M{"$in": ownerUserIDs}, + "friend_user_id": friendUserID, + } + 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) (int64, []*relation.FriendModel, error) { + filter := bson.M{"owner_user_id": ownerUserID} + 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.Pagination) (int64, []*relation.FriendModel, error) { + filter := bson.M{"friend_user_id": friendUserID} + 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} + 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 0000000000..c1be87ca24 --- /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/mgo/group.go b/pkg/common/db/mgo/group.go new file mode 100644 index 0000000000..3553b6b569 --- /dev/null +++ b/pkg/common/db/mgo/group.go @@ -0,0 +1,105 @@ +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 NewGroupMongo(db *mongo.Database) (relation.GroupModelInterface, error) { + 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 { + coll *mongo.Collection +} + +func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) { + return mgoutil.InsertMany(ctx, g.coll, groups) +} + +func (g *GroupMgo) UpdateState(ctx context.Context, groupID string, state int32) (err error) { + return g.UpdateMap(ctx, groupID, map[string]any{"state": state}) +} + +func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) { + if len(args) == 0 { + return nil + } + 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 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 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 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 mgoutil.Count(ctx, g.coll, bson.M{}) + } + 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) { + 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/mgo/group_member.go b/pkg/common/db/mgo/group_member.go new file mode 100644 index 0000000000..ed09a028bd --- /dev/null +++ b/pkg/common/db/mgo/group_member.go @@ -0,0 +1,101 @@ +package mgo + +import ( + "context" + + "github.com/OpenIMSDK/protocol/constant" + "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) { + 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 { + coll *mongo.Collection +} + +func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) { + return mgoutil.InsertMany(ctx, g.coll, groupMembers) +} + +func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) { + 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 { + return g.Update(ctx, groupID, userID, bson.M{"role_level": roleLevel}) +} + +func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) { + 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) { + //TODO implement me + panic("implement me") +} + +func (g *GroupMemberMgo) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) { + 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 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 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 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) { + //TODO implement me + panic("implement me") +} + +func (g *GroupMemberMgo) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { + 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 mgoutil.Count(ctx, g.coll, bson.M{"group_id": groupID}) +} + +func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) { + filter := bson.M{ + "user_id": userID, + "role_level": bson.M{ + "$in": []int{constant.GroupOwner, constant.GroupAdmin}, + }, + } + 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 { + if len(data) == 0 { + return false + } + _, ok := data["role_level"] + return ok +} diff --git a/pkg/common/db/mgo/group_request.go b/pkg/common/db/mgo/group_request.go new file mode 100644 index 0000000000..e88a39bf53 --- /dev/null +++ b/pkg/common/db/mgo/group_request.go @@ -0,0 +1,60 @@ +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 NewGroupRequestMgo(db *mongo.Database) (relation.GroupRequestModelInterface, error) { + 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 { + coll *mongo.Collection +} + +func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) { + return mgoutil.InsertMany(ctx, g.coll, groupRequests) +} + +func (g *GroupRequestMgo) Delete(ctx context.Context, groupID string, userID string) (err error) { + 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 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 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 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 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 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 0000000000..aa280fcf21 --- /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/mgo/object.go b/pkg/common/db/mgo/object.go new file mode 100644 index 0000000000..5976b2d28e --- /dev/null +++ b/pkg/common/db/mgo/object.go @@ -0,0 +1,55 @@ +package mgo + +import ( + "context" + + "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) { + 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 { + coll *mongo.Collection +} + +func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) error { + filter := bson.M{"name": obj.Name, "engine": obj.Engine} + update := bson.M{ + "name": obj.Name, + "engine": obj.Engine, + "key": obj.Key, + "size": obj.Size, + "content_type": obj.ContentType, + "group": obj.Group, + "create_time": obj.CreateTime, + } + 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 mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name}) + } + 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 mgoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine}) +} diff --git a/pkg/common/db/mgo/user.go b/pkg/common/db/mgo/user.go new file mode 100644 index 0000000000..4a53cb3c44 --- /dev/null +++ b/pkg/common/db/mgo/user.go @@ -0,0 +1,113 @@ +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 NewUserMongo(db *mongo.Database) (relation.UserModelInterface, error) { + 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 { + coll *mongo.Collection +} + +func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error { + 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 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 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 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 mgoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination) +} + +func (u *UserMgo) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (int64, []string, error) { + 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 mgoutil.Exist(ctx, u.coll, bson.M{"user_id": userID}) +} + +func (u *UserMgo) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) { + 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) { + 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) { + 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/relation/black_model.go b/pkg/common/db/relation/black_model.go deleted file mode 100644 index 34123c7a30..0000000000 --- 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]interface{}, -) (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 [][]interface{} - for _, black := range blacks { - where = append(where, []interface{}{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 f183a543f3..0000000000 --- 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 f39047bf63..0000000000 --- a/pkg/common/db/relation/conversation_model.go +++ /dev/null @@ -1,250 +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]interface{}, -) (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) GetUserAllHasReadSeqs( - ctx context.Context, - ownerUserID string, -) (hasReadSeqs map[string]int64, err error) { - return nil, nil -} - -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 41135ac977..0000000000 --- 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 869254455e..0000000000 --- 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]interface{}, -) (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]interface{}, 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 5678f7b7b2..0000000000 --- a/pkg/common/db/relation/friend_request_model.go +++ /dev/null @@ -1,164 +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 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]interface{}, -) (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 312e320546..0000000000 --- a/pkg/common/db/relation/group_member_model.go +++ /dev/null @@ -1,197 +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 7a8eee9f0b..0000000000 --- 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]interface{}) (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 af3f277e81..0000000000 --- a/pkg/common/db/relation/group_request_model.go +++ /dev/null @@ -1,118 +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 53365ca5b8..0000000000 --- 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/mysql_init.go b/pkg/common/db/relation/mysql_init.go deleted file mode 100644 index 41399d5cae..0000000000 --- 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 c321dfd9f3..0000000000 --- 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 c5624a8d4d..0000000000 --- a/pkg/common/db/relation/object_model.go +++ /dev/null @@ -1,53 +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 b04c298169..0000000000 --- a/pkg/common/db/relation/user_model.go +++ /dev/null @@ -1,136 +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{})} -} - -// 插入多条. -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]interface{}) (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/cont/controller.go b/pkg/common/db/s3/cont/controller.go index 7040c73068..1bf1a4b12c 100644 --- a/pkg/common/db/s3/cont/controller.go +++ b/pkg/common/db/s3/cont/controller.go @@ -46,6 +46,10 @@ type Controller struct { impl s3.Interface } +func (c *Controller) Engine() string { + return c.impl.Engine() +} + func (c *Controller) HashPath(md5 string) string { return path.Join(hashPath, md5) } diff --git a/pkg/common/db/s3/cos/internal.go b/pkg/common/db/s3/cos/internal.go index 0e58a851cf..02afde6845 100644 --- a/pkg/common/db/s3/cos/internal.go +++ b/pkg/common/db/s3/cos/internal.go @@ -10,4 +10,4 @@ import ( ) //go:linkname newRequest github.com/tencentyun/cos-go-sdk-v5.(*Client).newRequest -func newRequest(c *cos.Client, ctx context.Context, baseURL *url.URL, uri, method string, body interface{}, optQuery interface{}, optHeader interface{}) (req *http.Request, err error) +func newRequest(c *cos.Client, ctx context.Context, baseURL *url.URL, uri, method string, body any, optQuery any, optHeader any) (req *http.Request, err error) diff --git a/pkg/common/db/s3/kodo/internal.go b/pkg/common/db/s3/kodo/internal.go deleted file mode 100644 index 3a4943e628..0000000000 --- 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 d73220b3b4..0000000000 --- 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/internal.go b/pkg/common/db/s3/oss/internal.go index 4ca1acc47b..155708ffd7 100644 --- a/pkg/common/db/s3/oss/internal.go +++ b/pkg/common/db/s3/oss/internal.go @@ -26,7 +26,7 @@ import ( func signHeader(c oss.Conn, req *http.Request, canonicalizedResource string) //go:linkname getURLParams github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.getURLParams -func getURLParams(c oss.Conn, params map[string]interface{}) string +func getURLParams(c oss.Conn, params map[string]any) string //go:linkname getURL github.com/aliyun/aliyun-oss-go-sdk/oss.urlMaker.getURL func getURL(um urlMaker, bucket, object, params string) *url.URL 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 59dd12122c..50499054cc 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]interface{}) (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/conversation.go b/pkg/common/db/table/relation/conversation.go index e9680873fb..e0a5268caa 100644 --- a/pkg/common/db/table/relation/conversation.go +++ b/pkg/common/db/table/relation/conversation.go @@ -17,41 +17,35 @@ package relation import ( "context" "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"` -} - -func (ConversationModel) TableName() string { - return conversationModelTableName + OwnerUserID string `bson:"owner_user_id"` + ConversationID string `bson:"conversation_id"` + ConversationType int32 `bson:"conversation_type"` + UserID string `bson:"user_id"` + GroupID string `bson:"group_id"` + RecvMsgOpt int32 `bson:"recv_msg_opt"` + IsPinned bool `bson:"is_pinned"` + IsPrivateChat bool `bson:"is_private_chat"` + BurnDuration int32 `bson:"burn_duration"` + GroupAtType int32 `bson:"group_at_type"` + AttachedInfo string `bson:"attached_info"` + Ex string `bson:"ex"` + MaxSeq int64 `bson:"max_seq"` + MinSeq int64 `bson:"min_seq"` + CreateTime time.Time `bson:"create_time"` + IsMsgDestruct bool `bson:"is_msg_destruct"` + MsgDestructTime int64 `bson:"msg_destruct_time"` + LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"` } type ConversationModelInterface interface { Create(ctx context.Context, conversations []*ConversationModel) (err error) Delete(ctx context.Context, groupIDs []string) (err error) - UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) (rows int64, err error) + UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]any) (rows int64, err error) Update(ctx context.Context, conversation *ConversationModel) (err error) Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*ConversationModel, err error) FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) @@ -61,13 +55,10 @@ 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, pageNumber, showNumber int32) (conversationIDs []string, err error) - GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (hashReadSeqs map[string]int64, err error) + PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*ConversationModel, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*ConversationModel, error) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) - NewTx(tx any) ConversationModelInterface } diff --git a/pkg/common/db/table/relation/friend.go b/pkg/common/db/table/relation/friend.go index 58d8d1d344..75dbea850d 100644 --- a/pkg/common/db/table/relation/friend.go +++ b/pkg/common/db/table/relation/friend.go @@ -17,62 +17,43 @@ package relation import ( "context" "time" -) -const ( - FriendModelTableName = "friends" + "github.com/OpenIMSDK/tools/pagination" ) +// FriendModel represents the data structure for a friend relationship in MongoDB. type FriendModel struct { - 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"` -} - -func (FriendModel) TableName() string { - return FriendModelTableName + 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. type FriendModelInterface interface { - // 插入多条记录 + // Create inserts multiple friend records. Create(ctx context.Context, friends []*FriendModel) (err error) - // 删除ownerUserID指定的好友 + // Delete removes specified friends of the owner user. Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) - // 更新ownerUserID单个好友信息 更新零值 - UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error) - // 更新好友信息的非零值 - Update(ctx context.Context, friends []*FriendModel) (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) + // 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) - // 查找好友关系,如果是双向关系,则都返回 + // FindUserState finds the friendship status between two users. FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error) - // 获取 owner指定的好友列表 如果有friendUserIDs不存在,也不返回错误 + // FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error. FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error) - // 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在,也不返回错误 - FindReversalFriends( - ctx context.Context, - friendUserID string, - ownerUserIDs []string, - ) (friends []*FriendModel, err error) - // 获取ownerUserID好友列表 支持翻页 - FindOwnerFriends( - ctx context.Context, - ownerUserID string, - pageNumber, showNumber int32, - ) (friends []*FriendModel, total int64, err error) - // 获取哪些人添加了friendUserID 支持翻页 - FindInWhoseFriends( - ctx context.Context, - friendUserID string, - pageNumber, showNumber int32, - ) (friends []*FriendModel, total int64, err error) - // 获取好友UserID列表 + // 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, 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, 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(tx any) FriendModelInterface } diff --git a/pkg/common/db/table/relation/friend_request.go b/pkg/common/db/table/relation/friend_request.go index 51ea0ef6e3..8dceb0778c 100644 --- a/pkg/common/db/table/relation/friend_request.go +++ b/pkg/common/db/table/relation/friend_request.go @@ -17,50 +17,37 @@ package relation import ( "context" "time" -) -const FriendRequestModelTableName = "friend_requests" + "github.com/OpenIMSDK/tools/pagination" +) type FriendRequestModel struct { - FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` - ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` - HandleResult int32 `gorm:"column:handle_result"` - ReqMsg string `gorm:"column:req_msg;size:255"` - CreateTime time.Time `gorm:"column:create_time; autoCreateTime"` - HandlerUserID string `gorm:"column:handler_user_id;size:64"` - HandleMsg string `gorm:"column:handle_msg;size:255"` - HandleTime time.Time `gorm:"column:handle_time"` - Ex string `gorm:"column:ex;size:1024"` -} - -func (FriendRequestModel) TableName() string { - return FriendRequestModelTableName + 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 { - // 插入多条记录 + // Insert multiple records Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) - // 删除记录 + // Delete record Delete(ctx context.Context, fromUserID, toUserID string) (err error) - // 更新零值 - UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]interface{}) (err error) - // 更新多条记录 (非零值) + // Update with zero values + UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]any) (err error) + // Update multiple records (non-zero values) Update(ctx context.Context, friendRequest *FriendRequestModel) (err error) - // 获取来指定用户的好友申请 未找到 不返回错误 + // Get friend requests sent to a specific user, no error returned if not found Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) - // 获取toUserID收到的好友申请列表 - FindToUserID( - ctx context.Context, - toUserID string, - pageNumber, showNumber int32, - ) (friendRequests []*FriendRequestModel, total int64, err error) - // 获取fromUserID发出去的好友申请列表 - FindFromUserID( - ctx context.Context, - fromUserID string, - pageNumber, showNumber int32, - ) (friendRequests []*FriendRequestModel, total int64, err error) + // Get list of friend requests received by toUserID + 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, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) - NewTx(tx any) FriendRequestModelInterface } diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go index 6759e0d352..bb1ddd8789 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/db/table/relation/group.go @@ -17,48 +17,35 @@ package relation import ( "context" "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"` -} - -func (GroupModel) TableName() string { - return GroupModelTableName + GroupID string `bson:"group_id"` + GroupName string `bson:"group_name"` + Notification string `bson:"notification"` + Introduction string `bson:"introduction"` + FaceURL string `bson:"face_url"` + CreateTime time.Time `bson:"create_time"` + Ex string `bson:"ex"` + Status int32 `bson:"status"` + CreatorUserID string `bson:"creator_user_id"` + GroupType int32 `bson:"group_type"` + NeedVerification int32 `bson:"need_verification"` + LookMemberInfo int32 `bson:"look_member_info"` + ApplyMemberFriend int32 `bson:"apply_member_friend"` + NotificationUpdateTime time.Time `bson:"notification_update_time"` + NotificationUserID string `bson:"notification_user_id"` } type GroupModelInterface interface { - NewTx(tx any) GroupModelInterface Create(ctx context.Context, groups []*GroupModel) (err error) - UpdateMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) - UpdateStatus(ctx context.Context, groupID string, status int32) (err error) + UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error) + UpdateState(ctx context.Context, groupID string, state int32) (err error) Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) - FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) Take(ctx context.Context, groupID string) (group *GroupModel, err error) - Search( - ctx context.Context, - keyword string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupModel, err error) - GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*GroupModel, err error) // 获取群总数 CountTotal(ctx context.Context, before *time.Time) (count int64, err error) // 获取范围内群增量 diff --git a/pkg/common/db/table/relation/group_member.go b/pkg/common/db/table/relation/group_member.go index bfde728345..88ab87739d 100644 --- a/pkg/common/db/table/relation/group_member.go +++ b/pkg/common/db/table/relation/group_member.go @@ -17,58 +17,41 @@ package relation import ( "context" "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"` -} - -func (GroupMemberModel) TableName() string { - return GroupMemberModelTableName + GroupID string `bson:"group_id"` + UserID string `bson:"user_id"` + Nickname string `bson:"nickname"` + FaceURL string `bson:"face_url"` + RoleLevel int32 `bson:"role_level"` + JoinTime time.Time `bson:"join_time"` + JoinSource int32 `bson:"join_source"` + InviterUserID string `bson:"inviter_user_id"` + OperatorUserID string `bson:"operator_user_id"` + MuteEndTime time.Time `bson:"mute_end_time"` + Ex string `bson:"ex"` } type GroupMemberModelInterface interface { - NewTx(tx any) GroupMemberModelInterface + //NewTx(tx any) GroupMemberModelInterface Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) Delete(ctx context.Context, groupID string, userIDs []string) (err error) - DeleteGroup(ctx context.Context, groupIDs []string) (err error) + //DeleteGroup(ctx context.Context, groupIDs []string) (err error) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) - UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) (rowsAffected int64, err error) - Find( - ctx context.Context, - groupIDs []string, - userIDs []string, - roleLevels []int32, - ) (groupMembers []*GroupMemberModel, err error) + UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error) TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) - SearchMember( - ctx context.Context, - keyword string, - groupIDs []string, - userIDs []string, - roleLevels []int32, - pageNumber, showNumber int32, - ) (total uint32, groupList []*GroupMemberModel, err error) - MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) - FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) + SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*GroupMemberModel, err error) + FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + //MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) + //FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) - FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) + //FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) + IsUpdateRoleLevel(data map[string]any) bool } diff --git a/pkg/common/db/table/relation/group_request.go b/pkg/common/db/table/relation/group_request.go index 063b83938f..39999d799f 100644 --- a/pkg/common/db/table/relation/group_request.go +++ b/pkg/common/db/table/relation/group_request.go @@ -17,45 +17,30 @@ package relation import ( "context" "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"` -} - -func (GroupRequestModel) TableName() string { - return GroupRequestModelTableName + UserID string `bson:"user_id"` + GroupID string `bson:"group_id"` + HandleResult int32 `bson:"handle_result"` + ReqMsg string `bson:"req_msg"` + HandledMsg string `bson:"handled_msg"` + ReqTime time.Time `bson:"req_time"` + HandleUserID string `bson:"handle_user_id"` + HandledTime time.Time `bson:"handled_time"` + JoinSource int32 `bson:"join_source"` + InviterUserID string `bson:"inviter_user_id"` + Ex string `bson:"ex"` } type GroupRequestModelInterface interface { - NewTx(tx any) GroupRequestModelInterface Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) Delete(ctx context.Context, groupID string, userID string) (err error) UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) Take(ctx context.Context, groupID string, userID string) (groupRequest *GroupRequestModel, err error) - FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*GroupRequestModel, error) - Page( - ctx context.Context, - userID string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupRequestModel, err error) - PageGroup( - ctx context.Context, - groupIDs []string, - pageNumber, showNumber int32, - ) (total uint32, groups []*GroupRequestModel, err error) + FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*GroupRequestModel, error) + Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error) + PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error) } diff --git a/pkg/common/db/table/relation/log.go b/pkg/common/db/table/relation/log.go index 72d0fa64ef..f690ff8aa5 100644 --- a/pkg/common/db/table/relation/log.go +++ b/pkg/common/db/table/relation/log.go @@ -3,23 +3,25 @@ package relation import ( "context" "time" + + "github.com/OpenIMSDK/tools/pagination" ) -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)"` +type LogModel struct { + LogID string `bson:"log_id"` + Platform string `bson:"platform"` + UserID string `bson:"user_id"` + CreateTime time.Time `bson:"create_time"` + Url string `bson:"url"` + FileName string `bson:"file_name"` + SystemType string `bson:"system_type"` + Version string `bson:"version"` + Ex string `bson:"ex"` } type LogInterface interface { - Create(ctx context.Context, log []*Log) error - Search(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*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 0ed4130a64..678fddcfdb 100644 --- a/pkg/common/db/table/relation/object.go +++ b/pkg/common/db/table/relation/object.go @@ -19,27 +19,20 @@ import ( "time" ) -const ( - ObjectInfoModelTableName = "object" -) - type ObjectModel struct { - Name string `gorm:"column:name;primary_key"` - UserID string `gorm:"column:user_id"` - Hash string `gorm:"column:hash"` - 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 + Name string `bson:"name"` + UserID string `bson:"user_id"` + Hash string `bson:"hash"` + Engine string `bson:"engine"` + Key string `bson:"key"` + Size int64 `bson:"size"` + ContentType string `bson:"content_type"` + Group string `bson:"group"` + CreateTime time.Time `bson:"create_time"` } type ObjectInfoModelInterface interface { - NewTx(tx any) ObjectInfoModelInterface SetObject(ctx context.Context, obj *ObjectModel) error - Take(ctx context.Context, name string) (*ObjectModel, error) + Take(ctx context.Context, engine string, name string) (*ObjectModel, error) + Delete(ctx context.Context, engine string, name string) error } diff --git a/pkg/common/db/table/relation/user.go b/pkg/common/db/table/relation/user.go index 10a715bda8..1f26d751f5 100644 --- a/pkg/common/db/table/relation/user.go +++ b/pkg/common/db/table/relation/user.go @@ -17,20 +17,18 @@ package relation import ( "context" "time" -) -const ( - UserModelTableName = "users" + "github.com/OpenIMSDK/tools/pagination" ) type UserModel struct { - UserID string `gorm:"column:user_id;primary_key;size:64"` - Nickname string `gorm:"column:name;size:255"` - FaceURL string `gorm:"column:face_url;size:255"` - Ex string `gorm:"column:ex;size:1024"` - CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` - AppMangerLevel int32 `gorm:"column:app_manger_level;default:1"` - GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt"` + UserID string `bson:"user_id"` + Nickname string `bson:"nickname"` + FaceURL string `bson:"face_url"` + Ex string `bson:"ex"` + AppMangerLevel int32 `bson:"app_manger_level"` + GlobalRecvMsgOpt int32 `bson:"global_recv_msg_opt"` + CreateTime time.Time `bson:"create_time"` } func (u *UserModel) GetNickname() string { @@ -41,29 +39,22 @@ func (u *UserModel) GetFaceURL() string { return u.FaceURL } -func (u *UserModel) GetUserID() string { +func (u UserModel) GetUserID() string { return u.UserID } -func (u *UserModel) GetEx() string { +func (u UserModel) GetEx() string { return u.Ex } -func (UserModel) TableName() string { - return UserModelTableName -} - type UserModelInterface interface { Create(ctx context.Context, users []*UserModel) (err error) - UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) - Update(ctx context.Context, user *UserModel) (err error) - // 获取指定用户信息 不存在,也不返回错误 + UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) Find(ctx context.Context, userIDs []string) (users []*UserModel, err error) - // 获取某个用户信息 不存在,则返回错误 Take(ctx context.Context, userID string) (user *UserModel, err error) - // 获取用户信息 不存在,不返回错误 - Page(ctx context.Context, pageNumber, showNumber int32) (users []*UserModel, count int64, err error) - GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) + Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*UserModel, err error) + Exist(ctx context.Context, userID string) (exist bool, err error) + GetAllUserID(ctx context.Context, pagination pagination.Pagination) (count int64, userIDs []string, err error) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) // 获取用户总数 CountTotal(ctx context.Context, before *time.Time) (count int64, err error) diff --git a/pkg/common/db/table/relation/utils.go b/pkg/common/db/table/relation/utils.go index c944eae8b9..380f2410ea 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/table/unrelation/super_group.go b/pkg/common/db/table/unrelation/super_group.go index 80c3ef9c76..1fd80c67a7 100644 --- a/pkg/common/db/table/unrelation/super_group.go +++ b/pkg/common/db/table/unrelation/super_group.go @@ -14,40 +14,40 @@ package unrelation -import ( - "context" -) - -const ( - CSuperGroup = "super_group" - CUserToSuperGroup = "user_to_super_group" -) - -type SuperGroupModel struct { - GroupID string `bson:"group_id" json:"groupID"` - MemberIDs []string `bson:"member_id_list" json:"memberIDList"` -} - -func (SuperGroupModel) TableName() string { - return CSuperGroup -} - -type UserToSuperGroupModel struct { - UserID string `bson:"user_id" json:"userID"` - GroupIDs []string `bson:"group_id_list" json:"groupIDList"` -} - -func (UserToSuperGroupModel) TableName() string { - return CUserToSuperGroup -} - -type SuperGroupModelInterface interface { - CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error - TakeSuperGroup(ctx context.Context, groupID string) (group *SuperGroupModel, err error) - FindSuperGroup(ctx context.Context, groupIDs []string) (groups []*SuperGroupModel, err error) - AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error - RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error - GetSuperGroupByUserID(ctx context.Context, userID string) (*UserToSuperGroupModel, error) - DeleteSuperGroup(ctx context.Context, groupID string) error - RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error -} +//import ( +// "context" +//) +// +//const ( +// CSuperGroup = "super_group" +// CUserToSuperGroup = "user_to_super_group" +//) +// +//type SuperGroupModel struct { +// GroupID string `bson:"group_id" json:"groupID"` +// MemberIDs []string `bson:"member_id_list" json:"memberIDList"` +//} +// +//func (SuperGroupModel) TableName() string { +// return CSuperGroup +//} +// +//type UserToSuperGroupModel struct { +// UserID string `bson:"user_id" json:"userID"` +// GroupIDs []string `bson:"group_id_list" json:"groupIDList"` +//} +// +//func (UserToSuperGroupModel) TableName() string { +// return CUserToSuperGroup +//} +// +//type SuperGroupModelInterface interface { +// CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error +// TakeSuperGroup(ctx context.Context, groupID string) (group *SuperGroupModel, err error) +// FindSuperGroup(ctx context.Context, groupIDs []string) (groups []*SuperGroupModel, err error) +// AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error +// RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error +// GetSuperGroupByUserID(ctx context.Context, userID string) (*UserToSuperGroupModel, error) +// DeleteSuperGroup(ctx context.Context, groupID string) error +// RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error +//} diff --git a/pkg/common/db/unrelation/mongo.go b/pkg/common/db/unrelation/mongo.go old mode 100755 new mode 100644 index 09e3e904e2..38a3355674 --- a/pkg/common/db/unrelation/mongo.go +++ b/pkg/common/db/unrelation/mongo.go @@ -99,16 +99,6 @@ func (m *Mongo) CreateMsgIndex() error { return m.createMongoIndex(unrelation.Msg, true, "doc_id") } -func (m *Mongo) CreateSuperGroupIndex() error { - if err := m.createMongoIndex(unrelation.CSuperGroup, true, "group_id"); err != nil { - return err - } - if err := m.createMongoIndex(unrelation.CUserToSuperGroup, true, "user_id"); err != nil { - return err - } - return nil -} - func (m *Mongo) createMongoIndex(collection string, isUnique bool, keys ...string) error { db := m.db.Database(config.Config.Mongo.Database).Collection(collection) opts := options.CreateIndexes().SetMaxTime(10 * time.Second) 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/msg_convert.go b/pkg/common/db/unrelation/msg_convert.go index 810b4f4196..373bc843e6 100644 --- a/pkg/common/db/unrelation/msg_convert.go +++ b/pkg/common/db/unrelation/msg_convert.go @@ -48,7 +48,7 @@ func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs log.ZError(ctx, "convertAll delete many failed", err, "conversationID", conversationID) continue } - var newMsgDocs []interface{} + var newMsgDocs []any for _, msgDoc := range msgDocs { if int64(len(msgDoc.Msg)) == m.model.GetSingleGocMsgNum() { continue diff --git a/pkg/common/db/unrelation/super_group.go b/pkg/common/db/unrelation/super_group.go index c762140a25..6c2bb6aafb 100644 --- a/pkg/common/db/unrelation/super_group.go +++ b/pkg/common/db/unrelation/super_group.go @@ -14,149 +14,150 @@ package unrelation -import ( - "context" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/OpenIMSDK/tools/utils" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" -) - -func NewSuperGroupMongoDriver(database *mongo.Database) unrelation.SuperGroupModelInterface { - return &SuperGroupMongoDriver{ - superGroupCollection: database.Collection(unrelation.CSuperGroup), - userToSuperGroupCollection: database.Collection(unrelation.CUserToSuperGroup), - } -} - -type SuperGroupMongoDriver struct { - superGroupCollection *mongo.Collection - userToSuperGroupCollection *mongo.Collection -} - -func (s *SuperGroupMongoDriver) CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error { - _, err := s.superGroupCollection.InsertOne(ctx, &unrelation.SuperGroupModel{ - GroupID: groupID, - MemberIDs: initMemberIDs, - }) - if err != nil { - return err - } - for _, userID := range initMemberIDs { - _, err = s.userToSuperGroupCollection.UpdateOne( - ctx, - bson.M{"user_id": userID}, - bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, - &options.UpdateOptions{ - Upsert: utils.ToPtr(true), - }, - ) - if err != nil { - return err - } - } - return nil -} - -func (s *SuperGroupMongoDriver) TakeSuperGroup( - ctx context.Context, - groupID string, -) (group *unrelation.SuperGroupModel, err error) { - if err := s.superGroupCollection.FindOne(ctx, bson.M{"group_id": groupID}).Decode(&group); err != nil { - return nil, utils.Wrap(err, "") - } - return group, nil -} - -func (s *SuperGroupMongoDriver) FindSuperGroup( - ctx context.Context, - groupIDs []string, -) (groups []*unrelation.SuperGroupModel, err error) { - cursor, err := s.superGroupCollection.Find(ctx, bson.M{"group_id": bson.M{ - "$in": groupIDs, - }}) - if err != nil { - return nil, err - } - defer cursor.Close(ctx) - if err := cursor.All(ctx, &groups); err != nil { - return nil, utils.Wrap(err, "") - } - return groups, nil -} - -func (s *SuperGroupMongoDriver) AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error { - _, err := s.superGroupCollection.UpdateOne( - ctx, - bson.M{"group_id": groupID}, - bson.M{"$addToSet": bson.M{"member_id_list": bson.M{"$each": userIDs}}}, - ) - if err != nil { - return err - } - upsert := true - opts := &options.UpdateOptions{ - Upsert: &upsert, - } - for _, userID := range userIDs { - _, err = s.userToSuperGroupCollection.UpdateOne( - ctx, - bson.M{"user_id": userID}, - bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, - opts, - ) - if err != nil { - return utils.Wrap(err, "transaction failed") - } - } - return nil -} - -func (s *SuperGroupMongoDriver) RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error { - _, err := s.superGroupCollection.UpdateOne( - ctx, - bson.M{"group_id": groupID}, - bson.M{"$pull": bson.M{"member_id_list": bson.M{"$in": userIDs}}}, - ) - if err != nil { - return err - } - err = s.RemoveGroupFromUser(ctx, groupID, userIDs) - if err != nil { - return err - } - return nil -} - -func (s *SuperGroupMongoDriver) GetSuperGroupByUserID( - ctx context.Context, - userID string, -) (*unrelation.UserToSuperGroupModel, error) { - var user unrelation.UserToSuperGroupModel - err := s.userToSuperGroupCollection.FindOne(ctx, bson.M{"user_id": userID}).Decode(&user) - return &user, utils.Wrap(err, "") -} - -func (s *SuperGroupMongoDriver) DeleteSuperGroup(ctx context.Context, groupID string) error { - group, err := s.TakeSuperGroup(ctx, groupID) - if err != nil { - return err - } - if _, err := s.superGroupCollection.DeleteOne(ctx, bson.M{"group_id": groupID}); err != nil { - return utils.Wrap(err, "") - } - return s.RemoveGroupFromUser(ctx, groupID, group.MemberIDs) -} - -func (s *SuperGroupMongoDriver) RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error { - _, err := s.userToSuperGroupCollection.UpdateOne( - ctx, - bson.M{"user_id": bson.M{"$in": userIDs}}, - bson.M{"$pull": bson.M{"group_id_list": groupID}}, - ) - return utils.Wrap(err, "") -} +// +//import ( +// "context" +// +// "go.mongodb.org/mongo-driver/bson" +// "go.mongodb.org/mongo-driver/mongo" +// "go.mongodb.org/mongo-driver/mongo/options" +// +// "github.com/OpenIMSDK/tools/utils" +// +// "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" +//) +// +//func NewSuperGroupMongoDriver(database *mongo.Database) unrelation.SuperGroupModelInterface { +// return &SuperGroupMongoDriver{ +// superGroupCollection: database.Collection(unrelation.CSuperGroup), +// userToSuperGroupCollection: database.Collection(unrelation.CUserToSuperGroup), +// } +//} +// +//type SuperGroupMongoDriver struct { +// superGroupCollection *mongo.Collection +// userToSuperGroupCollection *mongo.Collection +//} +// +//func (s *SuperGroupMongoDriver) CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error { +// _, err := s.superGroupCollection.InsertOne(ctx, &unrelation.SuperGroupModel{ +// GroupID: groupID, +// MemberIDs: initMemberIDs, +// }) +// if err != nil { +// return err +// } +// for _, userID := range initMemberIDs { +// _, err = s.userToSuperGroupCollection.UpdateOne( +// ctx, +// bson.M{"user_id": userID}, +// bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, +// &options.UpdateOptions{ +// Upsert: utils.ToPtr(true), +// }, +// ) +// if err != nil { +// return err +// } +// } +// return nil +//} +// +//func (s *SuperGroupMongoDriver) TakeSuperGroup( +// ctx context.Context, +// groupID string, +//) (group *unrelation.SuperGroupModel, err error) { +// if err := s.superGroupCollection.FindOne(ctx, bson.M{"group_id": groupID}).Decode(&group); err != nil { +// return nil, utils.Wrap(err, "") +// } +// return group, nil +//} +// +//func (s *SuperGroupMongoDriver) FindSuperGroup( +// ctx context.Context, +// groupIDs []string, +//) (groups []*unrelation.SuperGroupModel, err error) { +// cursor, err := s.superGroupCollection.Find(ctx, bson.M{"group_id": bson.M{ +// "$in": groupIDs, +// }}) +// if err != nil { +// return nil, err +// } +// defer cursor.Close(ctx) +// if err := cursor.All(ctx, &groups); err != nil { +// return nil, utils.Wrap(err, "") +// } +// return groups, nil +//} +// +//func (s *SuperGroupMongoDriver) AddUserToSuperGroup(ctx context.Context, groupID string, userIDs []string) error { +// _, err := s.superGroupCollection.UpdateOne( +// ctx, +// bson.M{"group_id": groupID}, +// bson.M{"$addToSet": bson.M{"member_id_list": bson.M{"$each": userIDs}}}, +// ) +// if err != nil { +// return err +// } +// upsert := true +// opts := &options.UpdateOptions{ +// Upsert: &upsert, +// } +// for _, userID := range userIDs { +// _, err = s.userToSuperGroupCollection.UpdateOne( +// ctx, +// bson.M{"user_id": userID}, +// bson.M{"$addToSet": bson.M{"group_id_list": groupID}}, +// opts, +// ) +// if err != nil { +// return utils.Wrap(err, "transaction failed") +// } +// } +// return nil +//} +// +//func (s *SuperGroupMongoDriver) RemoverUserFromSuperGroup(ctx context.Context, groupID string, userIDs []string) error { +// _, err := s.superGroupCollection.UpdateOne( +// ctx, +// bson.M{"group_id": groupID}, +// bson.M{"$pull": bson.M{"member_id_list": bson.M{"$in": userIDs}}}, +// ) +// if err != nil { +// return err +// } +// err = s.RemoveGroupFromUser(ctx, groupID, userIDs) +// if err != nil { +// return err +// } +// return nil +//} +// +//func (s *SuperGroupMongoDriver) GetSuperGroupByUserID( +// ctx context.Context, +// userID string, +//) (*unrelation.UserToSuperGroupModel, error) { +// var user unrelation.UserToSuperGroupModel +// err := s.userToSuperGroupCollection.FindOne(ctx, bson.M{"user_id": userID}).Decode(&user) +// return &user, utils.Wrap(err, "") +//} +// +//func (s *SuperGroupMongoDriver) DeleteSuperGroup(ctx context.Context, groupID string) error { +// group, err := s.TakeSuperGroup(ctx, groupID) +// if err != nil { +// return err +// } +// if _, err := s.superGroupCollection.DeleteOne(ctx, bson.M{"group_id": groupID}); err != nil { +// return utils.Wrap(err, "") +// } +// return s.RemoveGroupFromUser(ctx, groupID, group.MemberIDs) +//} +// +//func (s *SuperGroupMongoDriver) RemoveGroupFromUser(ctx context.Context, groupID string, userIDs []string) error { +// _, err := s.userToSuperGroupCollection.UpdateOne( +// ctx, +// bson.M{"user_id": bson.M{"$in": userIDs}}, +// bson.M{"$pull": bson.M{"group_id_list": groupID}}, +// ) +// return utils.Wrap(err, "") +//} diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go old mode 100755 new mode 100644 diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go index f0fde3099b..e1bc83d38e 100644 --- a/pkg/common/http/http_client.go +++ b/pkg/common/http/http_client.go @@ -57,7 +57,7 @@ func Get(url string) (response []byte, err error) { return body, nil } -func Post(ctx context.Context, url string, header map[string]string, data interface{}, timeout int) (content []byte, err error) { +func Post(ctx context.Context, url string, header map[string]string, data any, timeout int) (content []byte, err error) { if timeout > 0 { var cancel func() ctx, cancel = context.WithTimeout(ctx, time.Second*time.Duration(timeout)) @@ -96,7 +96,7 @@ func Post(ctx context.Context, url string, header map[string]string, data interf return result, nil } -func PostReturn(ctx context.Context, url string, header map[string]string, input, output interface{}, timeOutSecond int) error { +func PostReturn(ctx context.Context, url string, header map[string]string, input, output any, timeOutSecond int) error { b, err := Post(ctx, url, header, input, timeOutSecond) if err != nil { return err diff --git a/pkg/common/http/http_client_test.go b/pkg/common/http/http_client_test.go index 1735a3da7c..5d25886736 100644 --- a/pkg/common/http/http_client_test.go +++ b/pkg/common/http/http_client_test.go @@ -54,7 +54,7 @@ func TestPost(t *testing.T) { ctx context.Context url string header map[string]string - data interface{} + data any timeout int } tests := []struct { @@ -84,8 +84,8 @@ func TestPostReturn(t *testing.T) { ctx context.Context url string header map[string]string - input interface{} - output interface{} + input any + output any timeOutSecond int } tests := []struct { @@ -109,7 +109,7 @@ func Test_callBackPostReturn(t *testing.T) { ctx context.Context url string command string - input interface{} + input any output callbackstruct.CallbackResp callbackConfig config.CallBackConfig } diff --git a/pkg/rpcclient/grouphash/grouphash.go b/pkg/rpcclient/grouphash/grouphash.go new file mode 100644 index 0000000000..b5570dccd4 --- /dev/null +++ b/pkg/rpcclient/grouphash/grouphash.go @@ -0,0 +1,88 @@ +package grouphash + +import ( + "context" + "crypto/md5" + "encoding/binary" + "encoding/json" + + "github.com/OpenIMSDK/protocol/group" + "github.com/OpenIMSDK/protocol/sdkws" + "github.com/OpenIMSDK/tools/utils" +) + +func NewGroupHashFromGroupClient(x group.GroupClient) *GroupHash { + return &GroupHash{ + getGroupAllUserIDs: func(ctx context.Context, groupID string) ([]string, error) { + resp, err := x.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID}) + if err != nil { + return nil, err + } + return resp.UserIDs, nil + }, + getGroupMemberInfo: func(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { + resp, err := x.GetGroupMembersInfo(ctx, &group.GetGroupMembersInfoReq{GroupID: groupID, UserIDs: userIDs}) + if err != nil { + return nil, err + } + return resp.Members, nil + }, + } +} + +func NewGroupHashFromGroupServer(x group.GroupServer) *GroupHash { + return &GroupHash{ + getGroupAllUserIDs: func(ctx context.Context, groupID string) ([]string, error) { + resp, err := x.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID}) + if err != nil { + return nil, err + } + return resp.UserIDs, nil + }, + getGroupMemberInfo: func(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { + resp, err := x.GetGroupMembersInfo(ctx, &group.GetGroupMembersInfoReq{GroupID: groupID, UserIDs: userIDs}) + if err != nil { + return nil, err + } + return resp.Members, nil + }, + } +} + +type GroupHash struct { + getGroupAllUserIDs func(ctx context.Context, groupID string) ([]string, error) + getGroupMemberInfo func(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) +} + +func (gh *GroupHash) GetGroupHash(ctx context.Context, groupID string) (uint64, error) { + userIDs, err := gh.getGroupAllUserIDs(ctx, groupID) + if err != nil { + return 0, err + } + var members []*sdkws.GroupMemberFullInfo + if len(userIDs) > 0 { + members, err = gh.getGroupMemberInfo(ctx, groupID, userIDs) + if err != nil { + return 0, err + } + utils.Sort(userIDs, true) + } + memberMap := utils.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string { + return e.UserID + }) + res := make([]*sdkws.GroupMemberFullInfo, 0, len(members)) + for _, userID := range userIDs { + member, ok := memberMap[userID] + if !ok { + continue + } + member.AppMangerLevel = 0 + res = append(res, member) + } + data, err := json.Marshal(res) + if err != nil { + return 0, err + } + sum := md5.Sum(data) + return binary.BigEndian.Uint64(sum[:]), nil +} diff --git a/pkg/rpcclient/notification/group.go b/pkg/rpcclient/notification/group.go index 8e71f61c38..cbae7c49b2 100755 --- a/pkg/rpcclient/notification/group.go +++ b/pkg/rpcclient/notification/group.go @@ -52,6 +52,41 @@ type GroupNotificationSender struct { db controller.GroupDatabase } +func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*relation.GroupMemberModel) error { + if len(members) == 0 { + return nil + } + emptyUserIDs := make(map[string]struct{}) + for _, member := range members { + if member.Nickname == "" || member.FaceURL == "" { + emptyUserIDs[member.UserID] = struct{}{} + } + } + if len(emptyUserIDs) > 0 { + users, err := g.getUsersInfo(ctx, utils.Keys(emptyUserIDs)) + if err != nil { + return err + } + userMap := make(map[string]CommonUser) + for i, user := range users { + userMap[user.GetUserID()] = users[i] + } + for i, member := range members { + user, ok := userMap[member.UserID] + if !ok { + continue + } + if member.Nickname == "" { + members[i].Nickname = user.GetNickname() + } + if member.FaceURL == "" { + members[i].FaceURL = user.GetFaceURL() + } + } + } + return nil +} + func (g *GroupNotificationSender) getUser(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) { users, err := g.getUsersInfo(ctx, []string{userID}) if err != nil { @@ -77,17 +112,21 @@ func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID stri if err != nil { return nil, err } - owner, err := g.db.TakeGroupOwner(ctx, groupID) + ownerUserIDs, err := g.db.GetGroupRoleLevelMemberIDs(ctx, groupID, constant.GroupOwner) if err != nil { return nil, err } + var ownerUserID string + if len(ownerUserIDs) > 0 { + ownerUserID = ownerUserIDs[0] + } return &sdkws.GroupInfo{ GroupID: gm.GroupID, GroupName: gm.GroupName, Notification: gm.Notification, Introduction: gm.Introduction, FaceURL: gm.FaceURL, - OwnerUserID: owner.UserID, + OwnerUserID: ownerUserID, CreateTime: gm.CreateTime.UnixMilli(), MemberCount: num, Ex: gm.Ex, @@ -103,39 +142,18 @@ func (g *GroupNotificationSender) getGroupInfo(ctx context.Context, groupID stri } func (g *GroupNotificationSender) getGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) { - members, err := g.db.FindGroupMember(ctx, []string{groupID}, userIDs, nil) + members, err := g.db.FindGroupMembers(ctx, groupID, userIDs) if err != nil { return nil, err } - log.ZDebug(ctx, "getGroupMembers", "members", members) - users, err := g.getUsersInfoMap(ctx, userIDs) - if err != nil { + if err := g.PopulateGroupMember(ctx, members...); err != nil { return nil, err } - log.ZDebug(ctx, "getUsersInfoMap", "users", users) + log.ZDebug(ctx, "getGroupMembers", "members", members) res := make([]*sdkws.GroupMemberFullInfo, 0, len(members)) for _, member := range members { - user, ok := users[member.UserID] - if !ok { - return nil, errs.ErrUserIDNotFound.Wrap(fmt.Sprintf("group %s member %s not in user", member.GroupID, member.UserID)) - } - if member.Nickname == "" { - member.Nickname = user.Nickname - } - res = append(res, g.groupMemberDB2PB(member, user.AppMangerLevel)) - delete(users, member.UserID) - } - //for userID, info := range users { - // if info.AppMangerLevel == constant.AppAdmin { - // res = append(res, &sdkws.GroupMemberFullInfo{ - // GroupID: groupID, - // UserID: userID, - // Nickname: info.Nickname, - // FaceURL: info.FaceURL, - // AppMangerLevel: info.AppMangerLevel, - // }) - // } - //} + res = append(res, g.groupMemberDB2PB(member, 0)) + } return res, nil } @@ -163,10 +181,13 @@ func (g *GroupNotificationSender) getGroupMember(ctx context.Context, groupID st } func (g *GroupNotificationSender) getGroupOwnerAndAdminUserID(ctx context.Context, groupID string) ([]string, error) { - members, err := g.db.FindGroupMember(ctx, []string{groupID}, nil, []int32{constant.GroupOwner, constant.GroupAdmin}) + members, err := g.db.FindGroupMemberRoleLevels(ctx, groupID, []int32{constant.GroupOwner, constant.GroupAdmin}) if err != nil { return nil, err } + if err := g.PopulateGroupMember(ctx, members...); err != nil { + return nil, err + } fn := func(e *relation.GroupMemberModel) string { return e.UserID } return utils.Slice(members, fn), nil } diff --git a/scripts/install/openim-tools.sh b/scripts/install/openim-tools.sh index fd95dc00da..f97b9d8360 100755 --- a/scripts/install/openim-tools.sh +++ b/scripts/install/openim-tools.sh @@ -61,6 +61,7 @@ openim::tools::pre_start_name() { local targets=( ncpu component + up35 ) echo "${targets[@]}" } diff --git a/test/e2e/api/token/token.go b/test/e2e/api/token/token.go index 679c0bbdad..4c578e8f70 100644 --- a/test/e2e/api/token/token.go +++ b/test/e2e/api/token/token.go @@ -125,7 +125,7 @@ func RegisterUser(token, userID, nickname, faceURL string) error { return err } - var respData map[string]interface{} + var respData map[string]any if err := json.Unmarshal(respBody, &respData); err != nil { return err } diff --git a/test/e2e/api/user/user.go b/test/e2e/api/user/user.go index 66419b7354..9facf76ac6 100644 --- a/test/e2e/api/user/user.go +++ b/test/e2e/api/user/user.go @@ -71,7 +71,7 @@ func GetUsers(token string, pageNumber, showNumber int) error { } // sendPostRequestWithToken sends a POST request with a token in the header -func sendPostRequestWithToken(url, token string, body interface{}) error { +func sendPostRequestWithToken(url, token string, body any) error { reqBytes, err := json.Marshal(body) if err != nil { return err @@ -98,7 +98,7 @@ func sendPostRequestWithToken(url, token string, body interface{}) error { return err } - var respData map[string]interface{} + var respData map[string]any if err := json.Unmarshal(respBody, &respData); err != nil { return err } diff --git a/test/jwt/main.go b/test/jwt/main.go index a669df9d63..0ef845237b 100644 --- a/test/jwt/main.go +++ b/test/jwt/main.go @@ -25,7 +25,7 @@ func main() { // Verify the token claims := &jwt.MapClaims{} - parsedT, err := jwt.ParseWithClaims(rawJWT, claims, func(token *jwt.Token) (interface{}, error) { + parsedT, err := jwt.ParseWithClaims(rawJWT, claims, func(token *jwt.Token) (any, error) { // Validate the alg is HMAC signature if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) diff --git a/test/typecheck/typecheck.go b/test/typecheck/typecheck.go index 0fc33597be..83e3c63ed9 100644 --- a/test/typecheck/typecheck.go +++ b/test/typecheck/typecheck.go @@ -239,7 +239,7 @@ func dedup(errors []packages.Error) []string { var outMu sync.Mutex -func serialFprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { +func serialFprintf(w io.Writer, format string, a ...any) (n int, err error) { outMu.Lock() defer outMu.Unlock() return fmt.Fprintf(w, format, a...) diff --git a/tools/component/component.go b/tools/component/component.go index 4e44bb7bab..140313c309 100644 --- a/tools/component/component.go +++ b/tools/component/component.go @@ -84,7 +84,7 @@ func main() { } checks := []checkFunc{ - {name: "Mysql", function: checkMysql}, + //{name: "Mysql", function: checkMysql}, {name: "Mongo", function: checkMongo}, {name: "Minio", function: checkMinio}, {name: "Redis", function: checkRedis}, @@ -133,6 +133,9 @@ func exactIP(urll string) string { } func checkMysql() error { + if config.Config.Mysql == nil { + return nil + } var sqlDB *sql.DB defer func() { if sqlDB != nil { diff --git a/tools/component/component_test.go b/tools/component/component_test.go index afa51ef2c9..08ea0fda8b 100644 --- a/tools/component/component_test.go +++ b/tools/component/component_test.go @@ -15,8 +15,12 @@ package main import ( + "context" + "strconv" "testing" + "time" + "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/openimsdk/open-im-server/v3/pkg/common/config" @@ -40,3 +44,43 @@ func mockInitCfg() error { config.Config.Mysql.Address = []string{"127.0.0.1:13306"} return nil } + +func TestRedis(t *testing.T) { + config.Config.Redis.Address = []string{ + "172.16.8.142:7000", + //"172.16.8.142:7000", "172.16.8.142:7001", "172.16.8.142:7002", "172.16.8.142:7003", "172.16.8.142:7004", "172.16.8.142:7005", + } + + var redisClient redis.UniversalClient + defer func() { + if redisClient != nil { + redisClient.Close() + } + }() + if len(config.Config.Redis.Address) > 1 { + redisClient = redis.NewClusterClient(&redis.ClusterOptions{ + Addrs: config.Config.Redis.Address, + Username: config.Config.Redis.Username, + Password: config.Config.Redis.Password, + }) + } else { + redisClient = redis.NewClient(&redis.Options{ + Addr: config.Config.Redis.Address[0], + Username: config.Config.Redis.Username, + Password: config.Config.Redis.Password, + }) + } + _, err := redisClient.Ping(context.Background()).Result() + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 1000000; i++ { + val, err := redisClient.Set(context.Background(), "b_"+strconv.Itoa(i), "test", time.Second*10).Result() + t.Log("index", i, "resp", val, "err", err) + if err != nil { + return + } + } + +} diff --git a/tools/data-conversion/README.md b/tools/data-conversion/README.md index 8d1bf86299..22126e4d86 100644 --- a/tools/data-conversion/README.md +++ b/tools/data-conversion/README.md @@ -13,8 +13,8 @@ ### 2. 迁移 OpenIM MySQL 数据 -+ 位置: `open-im-server/v3/tools/data-conversion/openim/mysql.go` -+ 配置 `mysql.go` 文件中的数据库信息。 ++ 位置: `open-im-server/tools/data-conversion/openim/cmd/conversion-mysql.go` ++ 配置 `conversion-mysql.go` 文件中的数据库信息。 + 手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。 ```bash @@ -47,7 +47,7 @@ make build BINS="conversion-mysql" ### 3. 转换聊天消息(可选) + 只支持转换存储在 Kafka 中的消息。 -+ 位置: `open-im-server/v3/tools/data-conversion/openim/msg.go` ++ 位置: `open-im-server/tools/data-conversion/openim/conversion-msg/conversion-msg.go` + 配置 `msg.go` 文件中的消息和服务器信息。 ```bash @@ -69,7 +69,7 @@ make build BINS="conversion-msg" ### 4. 转换业务服务器数据 + 只支持转换存储在 Kafka 中的消息。 -+ 位置: `open-im-server/v3/tools/data-conversion/chat/chat.go` ++ 位置: `open-im-server/tools/data-conversion/chat/cmd/conversion-chat/chat.go` + 需要手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。 + 配置 `main.go` 文件中的数据库信息。 diff --git a/tools/data-conversion/openim/mysql/conversion/conversion.go b/tools/data-conversion/openim/mysql/conversion/conversion.go index 298eefb50f..54cf90edf5 100644 --- a/tools/data-conversion/openim/mysql/conversion/conversion.go +++ b/tools/data-conversion/openim/mysql/conversion/conversion.go @@ -3,8 +3,8 @@ package conversion import ( "github.com/OpenIMSDK/protocol/constant" - v3 "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" v2 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v2" + v3 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v3" "github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils" ) diff --git a/tools/data-conversion/openim/mysql/v3/black.go b/tools/data-conversion/openim/mysql/v3/black.go new file mode 100644 index 0000000000..59dd12122c --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/black.go @@ -0,0 +1,49 @@ +// 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" +) + +const ( + BlackModelTableName = "blacks" +) + +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 +} + +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]interface{}) (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) + 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/tools/data-conversion/openim/mysql/v3/chatlog.go similarity index 100% rename from pkg/common/db/table/relation/chatlog.go rename to tools/data-conversion/openim/mysql/v3/chatlog.go diff --git a/tools/data-conversion/openim/mysql/v3/conversation.go b/tools/data-conversion/openim/mysql/v3/conversation.go new file mode 100644 index 0000000000..e9680873fb --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/conversation.go @@ -0,0 +1,73 @@ +// 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" +) + +const ( + conversationModelTableName = "conversations" +) + +type ConversationModel struct { + OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"` + ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"` + ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"` + UserID string `gorm:"column:user_id;type:char(64)" json:"userID"` + GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"` + RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"` + IsPinned bool `gorm:"column:is_pinned" json:"isPinned"` + IsPrivateChat bool `gorm:"column:is_private_chat" json:"isPrivateChat"` + BurnDuration int32 `gorm:"column:burn_duration;default:30" json:"burnDuration"` + GroupAtType int32 `gorm:"column:group_at_type" json:"groupAtType"` + AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"` + Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` + MaxSeq int64 `gorm:"column:max_seq" json:"maxSeq"` + MinSeq int64 `gorm:"column:min_seq" json:"minSeq"` + CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` + IsMsgDestruct bool `gorm:"column:is_msg_destruct;default:false"` + MsgDestructTime int64 `gorm:"column:msg_destruct_time;default:604800"` + LatestMsgDestructTime time.Time `gorm:"column:latest_msg_destruct_time;autoCreateTime"` +} + +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) + UpdateByMap(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) (rows int64, err error) + Update(ctx context.Context, conversation *ConversationModel) (err error) + Find(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []*ConversationModel, err error) + FindUserID(ctx context.Context, userIDs []string, conversationIDs []string) ([]string, error) + FindUserIDAllConversationID(ctx context.Context, userID string) ([]string, error) + Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error) + FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error) + 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, pageNumber, showNumber int32) (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) + NewTx(tx any) ConversationModelInterface +} diff --git a/pkg/common/db/table/relation/doc.go b/tools/data-conversion/openim/mysql/v3/doc.go similarity index 100% rename from pkg/common/db/table/relation/doc.go rename to tools/data-conversion/openim/mysql/v3/doc.go diff --git a/tools/data-conversion/openim/mysql/v3/friend.go b/tools/data-conversion/openim/mysql/v3/friend.go new file mode 100644 index 0000000000..58d8d1d344 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/friend.go @@ -0,0 +1,78 @@ +// 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" +) + +const ( + FriendModelTableName = "friends" +) + +type FriendModel struct { + 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"` +} + +func (FriendModel) TableName() string { + return FriendModelTableName +} + +type FriendModelInterface interface { + // 插入多条记录 + Create(ctx context.Context, friends []*FriendModel) (err error) + // 删除ownerUserID指定的好友 + Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) + // 更新ownerUserID单个好友信息 更新零值 + UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error) + // 更新好友信息的非零值 + Update(ctx context.Context, friends []*FriendModel) (err error) + // 更新好友备注(也支持零值 ) + UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) + // 获取单个好友信息,如没找到 返回错误 + Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error) + // 查找好友关系,如果是双向关系,则都返回 + FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error) + // 获取 owner指定的好友列表 如果有friendUserIDs不存在,也不返回错误 + FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error) + // 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在,也不返回错误 + FindReversalFriends( + ctx context.Context, + friendUserID string, + ownerUserIDs []string, + ) (friends []*FriendModel, err error) + // 获取ownerUserID好友列表 支持翻页 + FindOwnerFriends( + ctx context.Context, + ownerUserID string, + pageNumber, showNumber int32, + ) (friends []*FriendModel, total int64, err error) + // 获取哪些人添加了friendUserID 支持翻页 + FindInWhoseFriends( + ctx context.Context, + friendUserID string, + pageNumber, showNumber int32, + ) (friends []*FriendModel, total int64, err error) + // 获取好友UserID列表 + FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) + NewTx(tx any) FriendModelInterface +} diff --git a/tools/data-conversion/openim/mysql/v3/friend_request.go b/tools/data-conversion/openim/mysql/v3/friend_request.go new file mode 100644 index 0000000000..51ea0ef6e3 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/friend_request.go @@ -0,0 +1,66 @@ +// 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" +) + +const FriendRequestModelTableName = "friend_requests" + +type FriendRequestModel struct { + FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` + ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` + HandleResult int32 `gorm:"column:handle_result"` + ReqMsg string `gorm:"column:req_msg;size:255"` + CreateTime time.Time `gorm:"column:create_time; autoCreateTime"` + HandlerUserID string `gorm:"column:handler_user_id;size:64"` + HandleMsg string `gorm:"column:handle_msg;size:255"` + HandleTime time.Time `gorm:"column:handle_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +func (FriendRequestModel) TableName() string { + return FriendRequestModelTableName +} + +type FriendRequestModelInterface interface { + // 插入多条记录 + Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) + // 删除记录 + Delete(ctx context.Context, fromUserID, toUserID string) (err error) + // 更新零值 + UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]interface{}) (err error) + // 更新多条记录 (非零值) + Update(ctx context.Context, friendRequest *FriendRequestModel) (err error) + // 获取来指定用户的好友申请 未找到 不返回错误 + Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) + Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) + // 获取toUserID收到的好友申请列表 + FindToUserID( + ctx context.Context, + toUserID string, + pageNumber, showNumber int32, + ) (friendRequests []*FriendRequestModel, total int64, err error) + // 获取fromUserID发出去的好友申请列表 + FindFromUserID( + ctx context.Context, + fromUserID string, + pageNumber, showNumber int32, + ) (friendRequests []*FriendRequestModel, total int64, err error) + FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error) + NewTx(tx any) FriendRequestModelInterface +} diff --git a/tools/data-conversion/openim/mysql/v3/group.go b/tools/data-conversion/openim/mysql/v3/group.go new file mode 100644 index 0000000000..6759e0d352 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/group.go @@ -0,0 +1,66 @@ +// 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" +) + +const ( + GroupModelTableName = "groups" +) + +type GroupModel struct { + GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"` + GroupName string `gorm:"column:name;size:255" json:"groupName"` + Notification string `gorm:"column:notification;size:255" json:"notification"` + Introduction string `gorm:"column:introduction;size:255" json:"introduction"` + FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` + CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` + Ex string `gorm:"column:ex" json:"ex;size:1024"` + Status int32 `gorm:"column:status"` + CreatorUserID string `gorm:"column:creator_user_id;size:64"` + GroupType int32 `gorm:"column:group_type"` + NeedVerification int32 `gorm:"column:need_verification"` + LookMemberInfo int32 `gorm:"column:look_member_info" json:"lookMemberInfo"` + ApplyMemberFriend int32 `gorm:"column:apply_member_friend" json:"applyMemberFriend"` + NotificationUpdateTime time.Time `gorm:"column:notification_update_time"` + NotificationUserID string `gorm:"column:notification_user_id;size:64"` +} + +func (GroupModel) TableName() string { + return GroupModelTableName +} + +type GroupModelInterface interface { + NewTx(tx any) GroupModelInterface + Create(ctx context.Context, groups []*GroupModel) (err error) + UpdateMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) + UpdateStatus(ctx context.Context, groupID string, status int32) (err error) + Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) + FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) + Take(ctx context.Context, groupID string) (group *GroupModel, err error) + Search( + ctx context.Context, + keyword string, + pageNumber, showNumber int32, + ) (total uint32, groups []*GroupModel, err error) + GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) + // 获取群总数 + CountTotal(ctx context.Context, before *time.Time) (count int64, err error) + // 获取范围内群增量 + CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) +} diff --git a/tools/data-conversion/openim/mysql/v3/group_member.go b/tools/data-conversion/openim/mysql/v3/group_member.go new file mode 100644 index 0000000000..bfde728345 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/group_member.go @@ -0,0 +1,74 @@ +// 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" +) + +const ( + GroupMemberModelTableName = "group_members" +) + +type GroupMemberModel struct { + GroupID string `gorm:"column:group_id;primary_key;size:64"` + UserID string `gorm:"column:user_id;primary_key;size:64"` + Nickname string `gorm:"column:nickname;size:255"` + FaceURL string `gorm:"column:user_group_face_url;size:255"` + RoleLevel int32 `gorm:"column:role_level"` + JoinTime time.Time `gorm:"column:join_time"` + JoinSource int32 `gorm:"column:join_source"` + InviterUserID string `gorm:"column:inviter_user_id;size:64"` + OperatorUserID string `gorm:"column:operator_user_id;size:64"` + MuteEndTime time.Time `gorm:"column:mute_end_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +func (GroupMemberModel) TableName() string { + return GroupMemberModelTableName +} + +type GroupMemberModelInterface interface { + NewTx(tx any) GroupMemberModelInterface + Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) + Delete(ctx context.Context, groupID string, userIDs []string) (err error) + DeleteGroup(ctx context.Context, groupIDs []string) (err error) + Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) + UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) (rowsAffected int64, err error) + Find( + ctx context.Context, + groupIDs []string, + userIDs []string, + roleLevels []int32, + ) (groupMembers []*GroupMemberModel, err error) + FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error) + Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error) + TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) + SearchMember( + ctx context.Context, + keyword string, + groupIDs []string, + userIDs []string, + roleLevels []int32, + pageNumber, showNumber int32, + ) (total uint32, groupList []*GroupMemberModel, err error) + MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error) + FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error) + FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) + TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) + FindUsersJoinedGroupID(ctx context.Context, userIDs []string) (map[string][]string, error) + FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) +} diff --git a/tools/data-conversion/openim/mysql/v3/group_request.go b/tools/data-conversion/openim/mysql/v3/group_request.go new file mode 100644 index 0000000000..063b83938f --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/group_request.go @@ -0,0 +1,61 @@ +// 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" +) + +const ( + GroupRequestModelTableName = "group_requests" +) + +type GroupRequestModel struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + GroupID string `gorm:"column:group_id;primary_key;size:64"` + HandleResult int32 `gorm:"column:handle_result"` + ReqMsg string `gorm:"column:req_msg;size:1024"` + HandledMsg string `gorm:"column:handle_msg;size:1024"` + ReqTime time.Time `gorm:"column:req_time"` + HandleUserID string `gorm:"column:handle_user_id;size:64"` + HandledTime time.Time `gorm:"column:handle_time"` + JoinSource int32 `gorm:"column:join_source"` + InviterUserID string `gorm:"column:inviter_user_id;size:64"` + Ex string `gorm:"column:ex;size:1024"` +} + +func (GroupRequestModel) TableName() string { + return GroupRequestModelTableName +} + +type GroupRequestModelInterface interface { + NewTx(tx any) GroupRequestModelInterface + Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) + Delete(ctx context.Context, groupID string, userID string) (err error) + UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (err error) + Take(ctx context.Context, groupID string, userID string) (groupRequest *GroupRequestModel, err error) + FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*GroupRequestModel, error) + Page( + ctx context.Context, + userID string, + pageNumber, showNumber int32, + ) (total uint32, groups []*GroupRequestModel, err error) + PageGroup( + ctx context.Context, + groupIDs []string, + pageNumber, showNumber int32, + ) (total uint32, groups []*GroupRequestModel, err error) +} diff --git a/tools/data-conversion/openim/mysql/v3/log.go b/tools/data-conversion/openim/mysql/v3/log.go new file mode 100644 index 0000000000..5904a790e8 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/log.go @@ -0,0 +1,29 @@ +package relation + +import ( + "context" + "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)"` +} + +func (Log) TableName() string { + return "logs" +} + +type LogInterface interface { + Create(ctx context.Context, log []*Log) error + Search(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*Log, error) + Delete(ctx context.Context, logID []string, userID string) error + Get(ctx context.Context, logIDs []string, userID string) ([]*Log, error) +} diff --git a/tools/data-conversion/openim/mysql/v3/object.go b/tools/data-conversion/openim/mysql/v3/object.go new file mode 100644 index 0000000000..0ed4130a64 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/object.go @@ -0,0 +1,45 @@ +// 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" +) + +const ( + ObjectInfoModelTableName = "object" +) + +type ObjectModel struct { + Name string `gorm:"column:name;primary_key"` + UserID string `gorm:"column:user_id"` + Hash string `gorm:"column:hash"` + 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 { + NewTx(tx any) ObjectInfoModelInterface + SetObject(ctx context.Context, obj *ObjectModel) error + Take(ctx context.Context, name string) (*ObjectModel, error) +} diff --git a/tools/data-conversion/openim/mysql/v3/user.go b/tools/data-conversion/openim/mysql/v3/user.go new file mode 100644 index 0000000000..10a715bda8 --- /dev/null +++ b/tools/data-conversion/openim/mysql/v3/user.go @@ -0,0 +1,72 @@ +// 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" +) + +const ( + UserModelTableName = "users" +) + +type UserModel struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + Nickname string `gorm:"column:name;size:255"` + FaceURL string `gorm:"column:face_url;size:255"` + Ex string `gorm:"column:ex;size:1024"` + CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` + AppMangerLevel int32 `gorm:"column:app_manger_level;default:1"` + GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt"` +} + +func (u *UserModel) GetNickname() string { + return u.Nickname +} + +func (u *UserModel) GetFaceURL() string { + return u.FaceURL +} + +func (u *UserModel) GetUserID() string { + return u.UserID +} + +func (u *UserModel) GetEx() string { + return u.Ex +} + +func (UserModel) TableName() string { + return UserModelTableName +} + +type UserModelInterface interface { + Create(ctx context.Context, users []*UserModel) (err error) + UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) + Update(ctx context.Context, user *UserModel) (err error) + // 获取指定用户信息 不存在,也不返回错误 + Find(ctx context.Context, userIDs []string) (users []*UserModel, err error) + // 获取某个用户信息 不存在,则返回错误 + Take(ctx context.Context, userID string) (user *UserModel, err error) + // 获取用户信息 不存在,不返回错误 + Page(ctx context.Context, pageNumber, showNumber int32) (users []*UserModel, count int64, err error) + GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) + GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) + // 获取用户总数 + CountTotal(ctx context.Context, before *time.Time) (count int64, err error) + // 获取范围内用户增量 + CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) +} diff --git a/pkg/common/db/relation/meta_db.go b/tools/data-conversion/openim/mysql/v3/utils.go similarity index 70% rename from pkg/common/db/relation/meta_db.go rename to tools/data-conversion/openim/mysql/v3/utils.go index 6ab9801203..c944eae8b9 100644 --- a/pkg/common/db/relation/meta_db.go +++ b/tools/data-conversion/openim/mysql/v3/utils.go @@ -15,24 +15,22 @@ package relation import ( - "context" - "gorm.io/gorm" + + "github.com/OpenIMSDK/tools/utils" ) -type MetaDB struct { - DB *gorm.DB - table any +type BatchUpdateGroupMember struct { + GroupID string + UserID string + Map map[string]any } -func NewMetaDB(db *gorm.DB, table any) *MetaDB { - return &MetaDB{ - DB: db, - table: table, - } +type GroupSimpleUserID struct { + Hash uint64 + MemberNum uint32 } -func (g *MetaDB) db(ctx context.Context) *gorm.DB { - db := g.DB.WithContext(ctx).Model(g.table) - return db +func IsNotFound(err error) bool { + return utils.Unwrap(err) == gorm.ErrRecordNotFound } diff --git a/tools/data-conversion/openim/proto/msg/msg.pb.go b/tools/data-conversion/openim/proto/msg/msg.pb.go index 2954a3a769..a0a6cdf021 100644 --- a/tools/data-conversion/openim/proto/msg/msg.pb.go +++ b/tools/data-conversion/openim/proto/msg/msg.pb.go @@ -2703,7 +2703,7 @@ func RegisterMsgServer(s *grpc.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } -func _Msg_GetMaxAndMinSeq_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_GetMaxAndMinSeq_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(sdk_ws.GetMaxAndMinSeqReq) if err := dec(in); err != nil { return nil, err @@ -2715,13 +2715,13 @@ func _Msg_GetMaxAndMinSeq_Handler(srv interface{}, ctx context.Context, dec func Server: srv, FullMethod: "/msg.msg/GetMaxAndMinSeq", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).GetMaxAndMinSeq(ctx, req.(*sdk_ws.GetMaxAndMinSeqReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_PullMessageBySeqList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_PullMessageBySeqList_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(sdk_ws.PullMessageBySeqListReq) if err := dec(in); err != nil { return nil, err @@ -2733,13 +2733,13 @@ func _Msg_PullMessageBySeqList_Handler(srv interface{}, ctx context.Context, dec Server: srv, FullMethod: "/msg.msg/PullMessageBySeqList", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).PullMessageBySeqList(ctx, req.(*sdk_ws.PullMessageBySeqListReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_SendMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_SendMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(SendMsgReq) if err := dec(in); err != nil { return nil, err @@ -2751,13 +2751,13 @@ func _Msg_SendMsg_Handler(srv interface{}, ctx context.Context, dec func(interfa Server: srv, FullMethod: "/msg.msg/SendMsg", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).SendMsg(ctx, req.(*SendMsgReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_DelMsgList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_DelMsgList_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(sdk_ws.DelMsgListReq) if err := dec(in); err != nil { return nil, err @@ -2769,13 +2769,13 @@ func _Msg_DelMsgList_Handler(srv interface{}, ctx context.Context, dec func(inte Server: srv, FullMethod: "/msg.msg/DelMsgList", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).DelMsgList(ctx, req.(*sdk_ws.DelMsgListReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_DelSuperGroupMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_DelSuperGroupMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(DelSuperGroupMsgReq) if err := dec(in); err != nil { return nil, err @@ -2787,13 +2787,13 @@ func _Msg_DelSuperGroupMsg_Handler(srv interface{}, ctx context.Context, dec fun Server: srv, FullMethod: "/msg.msg/DelSuperGroupMsg", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).DelSuperGroupMsg(ctx, req.(*DelSuperGroupMsgReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_ClearMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_ClearMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(ClearMsgReq) if err := dec(in); err != nil { return nil, err @@ -2805,13 +2805,13 @@ func _Msg_ClearMsg_Handler(srv interface{}, ctx context.Context, dec func(interf Server: srv, FullMethod: "/msg.msg/ClearMsg", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).ClearMsg(ctx, req.(*ClearMsgReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_SetMsgMinSeq_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_SetMsgMinSeq_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(SetMsgMinSeqReq) if err := dec(in); err != nil { return nil, err @@ -2823,13 +2823,13 @@ func _Msg_SetMsgMinSeq_Handler(srv interface{}, ctx context.Context, dec func(in Server: srv, FullMethod: "/msg.msg/SetMsgMinSeq", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).SetMsgMinSeq(ctx, req.(*SetMsgMinSeqReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_SetSendMsgStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_SetSendMsgStatus_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(SetSendMsgStatusReq) if err := dec(in); err != nil { return nil, err @@ -2841,13 +2841,13 @@ func _Msg_SetSendMsgStatus_Handler(srv interface{}, ctx context.Context, dec fun Server: srv, FullMethod: "/msg.msg/SetSendMsgStatus", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).SetSendMsgStatus(ctx, req.(*SetSendMsgStatusReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_GetSendMsgStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_GetSendMsgStatus_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(GetSendMsgStatusReq) if err := dec(in); err != nil { return nil, err @@ -2859,13 +2859,13 @@ func _Msg_GetSendMsgStatus_Handler(srv interface{}, ctx context.Context, dec fun Server: srv, FullMethod: "/msg.msg/GetSendMsgStatus", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).GetSendMsgStatus(ctx, req.(*GetSendMsgStatusReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_GetSuperGroupMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_GetSuperGroupMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(GetSuperGroupMsgReq) if err := dec(in); err != nil { return nil, err @@ -2877,13 +2877,13 @@ func _Msg_GetSuperGroupMsg_Handler(srv interface{}, ctx context.Context, dec fun Server: srv, FullMethod: "/msg.msg/GetSuperGroupMsg", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).GetSuperGroupMsg(ctx, req.(*GetSuperGroupMsgReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_GetWriteDiffMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_GetWriteDiffMsg_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(GetWriteDiffMsgReq) if err := dec(in); err != nil { return nil, err @@ -2895,13 +2895,13 @@ func _Msg_GetWriteDiffMsg_Handler(srv interface{}, ctx context.Context, dec func Server: srv, FullMethod: "/msg.msg/GetWriteDiffMsg", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).GetWriteDiffMsg(ctx, req.(*GetWriteDiffMsgReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_SetMessageReactionExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_SetMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(SetMessageReactionExtensionsReq) if err := dec(in); err != nil { return nil, err @@ -2913,13 +2913,13 @@ func _Msg_SetMessageReactionExtensions_Handler(srv interface{}, ctx context.Cont Server: srv, FullMethod: "/msg.msg/SetMessageReactionExtensions", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).SetMessageReactionExtensions(ctx, req.(*SetMessageReactionExtensionsReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_GetMessageListReactionExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_GetMessageListReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(GetMessageListReactionExtensionsReq) if err := dec(in); err != nil { return nil, err @@ -2931,13 +2931,13 @@ func _Msg_GetMessageListReactionExtensions_Handler(srv interface{}, ctx context. Server: srv, FullMethod: "/msg.msg/GetMessageListReactionExtensions", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).GetMessageListReactionExtensions(ctx, req.(*GetMessageListReactionExtensionsReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_AddMessageReactionExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_AddMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(AddMessageReactionExtensionsReq) if err := dec(in); err != nil { return nil, err @@ -2949,13 +2949,13 @@ func _Msg_AddMessageReactionExtensions_Handler(srv interface{}, ctx context.Cont Server: srv, FullMethod: "/msg.msg/AddMessageReactionExtensions", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).AddMessageReactionExtensions(ctx, req.(*AddMessageReactionExtensionsReq)) } return interceptor(ctx, in, info, handler) } -func _Msg_DeleteMessageReactionExtensions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_DeleteMessageReactionExtensions_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(DeleteMessageListReactionExtensionsReq) if err := dec(in); err != nil { return nil, err @@ -2967,7 +2967,7 @@ func _Msg_DeleteMessageReactionExtensions_Handler(srv interface{}, ctx context.C Server: srv, FullMethod: "/msg.msg/DeleteMessageReactionExtensions", } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req any) (any, error) { return srv.(MsgServer).DeleteMessageReactionExtensions(ctx, req.(*DeleteMessageListReactionExtensionsReq)) } return interceptor(ctx, in, info, handler) diff --git a/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go b/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go index 0972808600..94b6f9be6b 100644 --- a/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go +++ b/tools/data-conversion/openim/proto/sdk_ws/ws.pb.go @@ -4156,8 +4156,8 @@ func (m *SignalReq) GetGetTokenByRoomID() *SignalGetTokenByRoomIDReq { } // XXX_OneofFuncs is for the internal use of the proto package. -func (*SignalReq) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _SignalReq_OneofMarshaler, _SignalReq_OneofUnmarshaler, _SignalReq_OneofSizer, []interface{}{ +func (*SignalReq) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []any) { + return _SignalReq_OneofMarshaler, _SignalReq_OneofUnmarshaler, _SignalReq_OneofSizer, []any{ (*SignalReq_Invite)(nil), (*SignalReq_InviteInGroup)(nil), (*SignalReq_Cancel)(nil), @@ -4523,8 +4523,8 @@ func (m *SignalResp) GetGetTokenByRoomID() *SignalGetTokenByRoomIDReply { } // XXX_OneofFuncs is for the internal use of the proto package. -func (*SignalResp) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _SignalResp_OneofMarshaler, _SignalResp_OneofUnmarshaler, _SignalResp_OneofSizer, []interface{}{ +func (*SignalResp) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []any) { + return _SignalResp_OneofMarshaler, _SignalResp_OneofUnmarshaler, _SignalResp_OneofSizer, []any{ (*SignalResp_Invite)(nil), (*SignalResp_InviteInGroup)(nil), (*SignalResp_Cancel)(nil), diff --git a/tools/up35/README.md b/tools/up35/README.md new file mode 100644 index 0000000000..c5bdcd3b62 --- /dev/null +++ b/tools/up35/README.md @@ -0,0 +1,67 @@ +# README for OpenIM Server Data Conversion Tool + +## Overview + +This tool is part of the OpenIM Server suite, specifically designed for data conversion between MySQL and MongoDB databases. It handles the migration of various data types, including user information, friendships, group memberships, and more from a MySQL database to MongoDB, ensuring data consistency and integrity during the transition. + +## Features + ++ **Configurable Database Connections:** Supports connections to both MySQL and MongoDB, configurable through a YAML file. ++ **Data Conversion Tasks:** Converts a range of data models, including user profiles, friend requests, group memberships, and logs. ++ **Version Control:** Maintains data versioning, ensuring only necessary migrations are performed. ++ **Error Handling:** Robust error handling for database connectivity and query execution. + +## Requirements + ++ Go programming environment ++ MySQL and MongoDB servers ++ OpenIM Server dependencies installed + +## Installation + +1. Ensure Go is installed and set up on your system. +2. Clone the OpenIM Server repository. +3. Navigate to the directory containing this tool. +4. Install required dependencies. + +## Configuration + ++ Configuration is managed through a YAML file specified at runtime. ++ Set up the MySQL and MongoDB connection parameters in the config file. + +## Usage + +To run the tool, use the following command from the terminal: + +```go +make build BINS="up35" +``` + +Where `path/to/config.yaml` is the path to your configuration file. + +## Functionality + +The main functions of the script include: + ++ `InitConfig(path string)`: Reads and parses the YAML configuration file. ++ `GetMysql()`: Establishes a connection to the MySQL database. ++ `GetMongo()`: Establishes a connection to the MongoDB database. ++ `Main(path string)`: Orchestrates the data migration process. ++ `SetMongoDataVersion(db *mongo.Database, curver string)`: Updates the data version in MongoDB after migration. ++ `NewTask(...)`: Generic function to handle the migration of different data types. ++ `insertMany(coll *mongo.Collection, objs []any)`: Inserts multiple records into a MongoDB collection. ++ `getColl(obj any)`: Retrieves the MongoDB collection associated with a given object. ++ `convert struct`: Contains methods for converting MySQL models to MongoDB models. + +## Notes + ++ Ensure that the MySQL and MongoDB instances are accessible and that the credentials provided in the config file are correct. ++ It is advisable to backup databases before running the migration to prevent data loss. + +## Contributing + +Contributions to improve the tool or address issues are welcome. Please follow the project's contribution guidelines. + +## License + +Refer to the project's license document for usage and distribution rights. \ No newline at end of file diff --git a/tools/up35/go.mod b/tools/up35/go.mod new file mode 100644 index 0000000000..5ae3907bff --- /dev/null +++ b/tools/up35/go.mod @@ -0,0 +1,51 @@ +module github.com/openimsdk/open-im-server/v3/tools/up35 + +go 1.19 + +require ( + github.com/go-sql-driver/mysql v1.7.1 + github.com/openimsdk/open-im-server/v3 v3.5.0 + github.com/openimsdk/open-im-server/v3/tools/data-conversion v0.0.0-00010101000000-000000000000 + go.mongodb.org/mongo-driver v1.12.1 + gopkg.in/yaml.v3 v3.0.1 + gorm.io/driver/mysql v1.5.1 + gorm.io/gorm v1.25.4 +) + +require ( + github.com/OpenIMSDK/protocol v0.0.31 // indirect + github.com/OpenIMSDK/tools v0.0.18 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/jinzhu/copier v0.4.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect + github.com/lestrrat-go/strftime v1.0.6 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/image v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect +) + +replace ( + github.com/openimsdk/open-im-server/v3 => ./../../../open-im-server + github.com/openimsdk/open-im-server/v3/tools/data-conversion => ./../data-conversion +) diff --git a/tools/up35/go.sum b/tools/up35/go.sum new file mode 100644 index 0000000000..1a81e5b338 --- /dev/null +++ b/tools/up35/go.sum @@ -0,0 +1,125 @@ +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.18 h1:h3CvKB90DNd2aIJcOQ99cqgeW6C0na0PzR1TNsfxwL0= +github.com/OpenIMSDK/tools v0.0.18/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +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= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= +github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= +golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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.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= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= +gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= +gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/tools/up35/up35.go b/tools/up35/up35.go new file mode 100644 index 0000000000..5d4740fca0 --- /dev/null +++ b/tools/up35/up35.go @@ -0,0 +1,367 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "github.com/go-sql-driver/mysql" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" + mongoModel "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" + mysqlModel "github.com/openimsdk/open-im-server/v3/tools/data-conversion/openim/mysql/v3" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gopkg.in/yaml.v3" + gormMysql "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "log" + "os" + "reflect" + "strconv" +) + +const ( + versionTable = "dataver" + versionKey = "data_version" + versionValue = 35 +) + +func main() { + var path string + flag.StringVar(&path, "c", "", "path config file") + flag.Parse() + if err := Main(path); err != nil { + log.Fatal(err) + return + } + os.Exit(0) +} + +func InitConfig(path string) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + return yaml.Unmarshal(data, &config.Config) +} + +func GetMysql() (*gorm.DB, error) { + conf := config.Config.Mysql + mysqlDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", conf.Username, conf.Password, conf.Address[0], conf.Database) + return gorm.Open(gormMysql.Open(mysqlDSN), &gorm.Config{Logger: logger.Discard}) +} + +func GetMongo() (*mongo.Database, error) { + mgo, err := unrelation.NewMongo() + if err != nil { + return nil, err + } + return mgo.GetDatabase(), nil +} + +func Main(path string) error { + if err := InitConfig(path); err != nil { + return err + } + if config.Config.Mysql == nil { + return nil + } + mongoDB, err := GetMongo() + if err != nil { + return err + } + var version struct { + Key string `bson:"key"` + Value string `bson:"value"` + } + switch mongoDB.Collection(versionTable).FindOne(context.Background(), bson.M{"key": versionKey}).Decode(&version) { + case nil: + if ver, _ := strconv.Atoi(version.Value); ver >= versionValue { + return nil + } + case mongo.ErrNoDocuments: + default: + return err + } + mysqlDB, err := GetMysql() + if err != nil { + if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1049 { + if err := SetMongoDataVersion(mongoDB, version.Value); err != nil { + return err + } + return nil // database not exist + } + return err + } + + var c convert + var tasks []func() error + tasks = append(tasks, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewUserMongo, c.User) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewFriendMongo, c.Friend) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewFriendRequestMongo, c.FriendRequest) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewBlackMongo, c.Black) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMongo, c.Group) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupMember, c.GroupMember) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewGroupRequestMgo, c.GroupRequest) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewConversationMongo, c.Conversation) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewS3Mongo, c.Object(config.Config.Object.Enable)) }, + func() error { return NewTask(mysqlDB, mongoDB, mgo.NewLogMongo, c.Log) }, + ) + + for _, task := range tasks { + if err := task(); err != nil { + return err + } + } + + if err := SetMongoDataVersion(mongoDB, version.Value); err != nil { + return err + } + return nil +} + +func SetMongoDataVersion(db *mongo.Database, curver string) error { + filter := bson.M{"key": versionKey, "value": curver} + update := bson.M{"$set": bson.M{"key": versionKey, "value": strconv.Itoa(versionValue)}} + _, err := db.Collection(versionTable).UpdateOne(context.Background(), filter, update, options.Update().SetUpsert(true)) + return err +} + +// NewTask A mysql table B mongodb model C mongodb table +func NewTask[A interface{ TableName() string }, B any, C any](gormDB *gorm.DB, mongoDB *mongo.Database, mongoDBInit func(db *mongo.Database) (B, error), convert func(v A) C) error { + obj, err := mongoDBInit(mongoDB) + if err != nil { + return err + } + var zero A + tableName := zero.TableName() + coll, err := getColl(obj) + if err != nil { + return fmt.Errorf("get mongo collection %s failed, err: %w", tableName, err) + } + var count int + defer func() { + log.Printf("completed convert %s total %d\n", tableName, count) + }() + const batch = 100 + for page := 0; ; page++ { + res := make([]A, 0, batch) + if err := gormDB.Limit(batch).Offset(page * batch).Find(&res).Error; err != nil { + if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1146 { + return nil // table not exist + } + return fmt.Errorf("find mysql table %s failed, err: %w", tableName, err) + } + if len(res) == 0 { + return nil + } + temp := make([]any, len(res)) + for i := range res { + temp[i] = convert(res[i]) + } + if err := insertMany(coll, temp); err != nil { + return fmt.Errorf("insert mongo table %s failed, err: %w", tableName, err) + } + count += len(res) + if len(res) < batch { + return nil + } + log.Printf("current convert %s completed %d\n", tableName, count) + } +} + +func insertMany(coll *mongo.Collection, objs []any) error { + if _, err := coll.InsertMany(context.Background(), objs); err != nil { + if !mongo.IsDuplicateKeyError(err) { + return err + } + } + for i := range objs { + _, err := coll.InsertOne(context.Background(), objs[i]) + switch { + case err == nil: + case mongo.IsDuplicateKeyError(err): + default: + return err + } + } + return nil +} + +func getColl(obj any) (_ *mongo.Collection, err error) { + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("not found %+v", e) + } + }() + stu := reflect.ValueOf(obj).Elem() + typ := reflect.TypeOf(&mongo.Collection{}).String() + for i := 0; i < stu.NumField(); i++ { + field := stu.Field(i) + if field.Type().String() == typ { + return (*mongo.Collection)(field.UnsafePointer()), nil + } + } + return nil, errors.New("not found") +} + +type convert struct{} + +func (convert) User(v mysqlModel.UserModel) mongoModel.UserModel { + return mongoModel.UserModel{ + UserID: v.UserID, + Nickname: v.Nickname, + FaceURL: v.FaceURL, + Ex: v.Ex, + AppMangerLevel: v.AppMangerLevel, + GlobalRecvMsgOpt: v.GlobalRecvMsgOpt, + CreateTime: v.CreateTime, + } +} + +func (convert) Friend(v mysqlModel.FriendModel) mongoModel.FriendModel { + return mongoModel.FriendModel{ + OwnerUserID: v.OwnerUserID, + FriendUserID: v.FriendUserID, + Remark: v.Remark, + CreateTime: v.CreateTime, + AddSource: v.AddSource, + OperatorUserID: v.OperatorUserID, + Ex: v.Ex, + } +} + +func (convert) FriendRequest(v mysqlModel.FriendRequestModel) mongoModel.FriendRequestModel { + return mongoModel.FriendRequestModel{ + FromUserID: v.FromUserID, + ToUserID: v.ToUserID, + HandleResult: v.HandleResult, + ReqMsg: v.ReqMsg, + CreateTime: v.CreateTime, + HandlerUserID: v.HandlerUserID, + HandleMsg: v.HandleMsg, + HandleTime: v.HandleTime, + Ex: v.Ex, + } +} + +func (convert) Black(v mysqlModel.BlackModel) mongoModel.BlackModel { + return mongoModel.BlackModel{ + OwnerUserID: v.OwnerUserID, + BlockUserID: v.BlockUserID, + CreateTime: v.CreateTime, + AddSource: v.AddSource, + OperatorUserID: v.OperatorUserID, + Ex: v.Ex, + } +} + +func (convert) Group(v mysqlModel.GroupModel) mongoModel.GroupModel { + return mongoModel.GroupModel{ + GroupID: v.GroupID, + GroupName: v.GroupName, + Notification: v.Notification, + Introduction: v.Introduction, + FaceURL: v.FaceURL, + CreateTime: v.CreateTime, + Ex: v.Ex, + Status: v.Status, + CreatorUserID: v.CreatorUserID, + GroupType: v.GroupType, + NeedVerification: v.NeedVerification, + LookMemberInfo: v.LookMemberInfo, + ApplyMemberFriend: v.ApplyMemberFriend, + NotificationUpdateTime: v.NotificationUpdateTime, + NotificationUserID: v.NotificationUserID, + } +} + +func (convert) GroupMember(v mysqlModel.GroupMemberModel) mongoModel.GroupMemberModel { + return mongoModel.GroupMemberModel{ + GroupID: v.GroupID, + UserID: v.UserID, + Nickname: v.Nickname, + FaceURL: v.FaceURL, + RoleLevel: v.RoleLevel, + JoinTime: v.JoinTime, + JoinSource: v.JoinSource, + InviterUserID: v.InviterUserID, + OperatorUserID: v.OperatorUserID, + MuteEndTime: v.MuteEndTime, + Ex: v.Ex, + } +} + +func (convert) GroupRequest(v mysqlModel.GroupRequestModel) mongoModel.GroupRequestModel { + return mongoModel.GroupRequestModel{ + UserID: v.UserID, + GroupID: v.GroupID, + HandleResult: v.HandleResult, + ReqMsg: v.ReqMsg, + HandledMsg: v.HandledMsg, + ReqTime: v.ReqTime, + HandleUserID: v.HandleUserID, + HandledTime: v.HandledTime, + JoinSource: v.JoinSource, + InviterUserID: v.InviterUserID, + Ex: v.Ex, + } +} + +func (convert) Conversation(v mysqlModel.ConversationModel) mongoModel.ConversationModel { + return mongoModel.ConversationModel{ + OwnerUserID: v.OwnerUserID, + ConversationID: v.ConversationID, + ConversationType: v.ConversationType, + UserID: v.UserID, + GroupID: v.GroupID, + RecvMsgOpt: v.RecvMsgOpt, + IsPinned: v.IsPinned, + IsPrivateChat: v.IsPrivateChat, + BurnDuration: v.BurnDuration, + GroupAtType: v.GroupAtType, + AttachedInfo: v.AttachedInfo, + Ex: v.Ex, + MaxSeq: v.MaxSeq, + MinSeq: v.MinSeq, + CreateTime: v.CreateTime, + IsMsgDestruct: v.IsMsgDestruct, + MsgDestructTime: v.MsgDestructTime, + LatestMsgDestructTime: v.LatestMsgDestructTime, + } +} + +func (convert) Object(engine string) func(v mysqlModel.ObjectModel) mongoModel.ObjectModel { + return func(v mysqlModel.ObjectModel) mongoModel.ObjectModel { + return mongoModel.ObjectModel{ + Name: v.Name, + UserID: v.UserID, + Hash: v.Hash, + Engine: engine, + Key: v.Key, + Size: v.Size, + ContentType: v.ContentType, + Group: v.Cause, + CreateTime: v.CreateTime, + } + } +} + +func (convert) Log(v mysqlModel.Log) mongoModel.LogModel { + return mongoModel.LogModel{ + LogID: v.LogID, + Platform: v.Platform, + UserID: v.UserID, + CreateTime: v.CreateTime, + Url: v.Url, + FileName: v.FileName, + SystemType: v.SystemType, + Version: v.Version, + Ex: v.Ex, + } +}