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 <withchao@users.noreply.github.com>
Co-authored-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com>
Co-authored-by: Xinwei Xiong <3293172751@qq.com>
This commit is contained in:
chao 2023-12-05 20:53:02 +08:00 committed by GitHub
parent 1c1322e3d2
commit c0194f6ef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
141 changed files with 4273 additions and 4858 deletions

View File

@ -24,6 +24,7 @@ services:
restart: always restart: always
networks: networks:
server: server:
# open-im-server_server
ipv4_address: ${MYSQL_NETWORK_ADDRESS} ipv4_address: ${MYSQL_NETWORK_ADDRESS}
mongodb: mongodb:
@ -142,68 +143,68 @@ services:
server: server:
ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS} ipv4_address: ${OPENIM_WEB_NETWORK_ADDRESS}
openim-admin: # openim-admin:
image: ${IMAGE_REGISTRY}/openim-admin-front:v3.4.0 # image: ${IMAGE_REGISTRY}/openim-admin-front:v3.4.0
# image: ghcr.io/openimsdk/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: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-admin-front:v3.4.0
# image: openim/openim-admin-front:v3.4.0 # # image: openim/openim-admin-front:v3.4.0
container_name: openim-admin # container_name: openim-admin
restart: always # restart: always
ports: # ports:
- "${OPENIM_ADMIN_FRONT_PORT}:80" # - "${OPENIM_ADMIN_FRONT_PORT}:80"
networks: # networks:
server: # server:
ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS} # ipv4_address: ${OPENIM_ADMIN_FRONT_NETWORK_ADDRESS}
prometheus: # prometheus:
image: prom/prometheus # image: prom/prometheus
container_name: prometheus # container_name: prometheus
hostname: prometheus # hostname: prometheus
restart: always # restart: always
volumes: # volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml # - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
- ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml # - ./config/instance-down-rules.yml:/etc/prometheus/instance-down-rules.yml
ports: # ports:
- "${PROMETHEUS_PORT}:9090" # - "${PROMETHEUS_PORT}:9090"
networks: # networks:
server: # server:
ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS} # ipv4_address: ${PROMETHEUS_NETWORK_ADDRESS}
alertmanager: # alertmanager:
image: prom/alertmanager # image: prom/alertmanager
container_name: alertmanager # container_name: alertmanager
hostname: alertmanager # hostname: alertmanager
restart: always # restart: always
volumes: # volumes:
- ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml # - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
- ./config/email.tmpl:/etc/alertmanager/email.tmpl # - ./config/email.tmpl:/etc/alertmanager/email.tmpl
ports: # ports:
- "${ALERT_MANAGER_PORT}:9093" # - "${ALERT_MANAGER_PORT}:9093"
networks: # networks:
server: # server:
ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS} # ipv4_address: ${ALERT_MANAGER_NETWORK_ADDRESS}
grafana: # grafana:
image: grafana/grafana # image: grafana/grafana
container_name: grafana # container_name: grafana
hostname: grafana # hostname: grafana
user: root # user: root
restart: always # restart: always
ports: # ports:
- "${GRAFANA_PORT}:3000" # - "${GRAFANA_PORT}:3000"
volumes: # volumes:
- ${DATA_DIR}/components/grafana:/var/lib/grafana # - ${DATA_DIR}/components/grafana:/var/lib/grafana
networks: # networks:
server: # server:
ipv4_address: ${GRAFANA_NETWORK_ADDRESS} # ipv4_address: ${GRAFANA_NETWORK_ADDRESS}
node-exporter: # node-exporter:
image: quay.io/prometheus/node-exporter # image: quay.io/prometheus/node-exporter
container_name: node-exporter # container_name: node-exporter
hostname: node-exporter # hostname: node-exporter
restart: always # restart: always
ports: # ports:
- "${NODE_EXPORTER_PORT}:9100" # - "${NODE_EXPORTER_PORT}:9100"
networks: # networks:
server: # server:
ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS} # ipv4_address: ${NODE_EXPORTER_NETWORK_ADDRESS}

12
go.mod
View File

@ -10,10 +10,8 @@ require (
github.com/go-playground/validator/v10 v10.15.5 github.com/go-playground/validator/v10 v10.15.5
github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt/v4 v4.5.0 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/gorilla/websocket v1.5.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.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/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/minio/minio-go/v7 v7.0.63 github.com/minio/minio-go/v7 v7.0.63
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
@ -29,8 +27,6 @@ require (
google.golang.org/grpc v1.59.0 google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/yaml.v3 v3.0.1 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 require github.com/google/uuid v1.3.1
@ -38,10 +34,9 @@ require github.com/google/uuid v1.3.1
require ( require (
github.com/IBM/sarama v1.41.3 github.com/IBM/sarama v1.41.3
github.com/OpenIMSDK/protocol v0.0.31 github.com/OpenIMSDK/protocol v0.0.31
github.com/OpenIMSDK/tools v0.0.17 github.com/OpenIMSDK/tools v0.0.18
github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible
github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.7.1
github.com/redis/go-redis/v9 v9.2.1 github.com/redis/go-redis/v9 v9.2.1
github.com/tencentyun/cos-go-sdk-v5 v0.7.45 github.com/tencentyun/cos-go-sdk-v5 v0.7.45
go.uber.org/automaxprocs v1.5.3 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-playground/universal-translator v0.18.1 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // 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/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.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/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // 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/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // 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/arch v0.3.0 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.13.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/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // 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 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/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gorm.io/gorm v1.23.8 // indirect
) )
require ( require (

4
go.sum
View File

@ -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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

@ -13,4 +13,5 @@ use (
./tools/component ./tools/component
./tools/url2im ./tools/url2im
./tools/data-conversion ./tools/data-conversion
./tools/up35
) )

View File

@ -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) { 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) log.ZDebug(c, "getSendMsgReq", "req", req.Content)
switch req.ContentType { switch req.ContentType {
case constant.Text: case constant.Text:

View File

@ -22,8 +22,8 @@ import (
) )
type Encoder interface { type Encoder interface {
Encode(data interface{}) ([]byte, error) Encode(data any) ([]byte, error)
Decode(encodeData []byte, decodeData interface{}) error Decode(encodeData []byte, decodeData any) error
} }
type GobEncoder struct{} type GobEncoder struct{}
@ -32,7 +32,7 @@ func NewGobEncoder() *GobEncoder {
return &GobEncoder{} return &GobEncoder{}
} }
func (g *GobEncoder) Encode(data interface{}) ([]byte, error) { func (g *GobEncoder) Encode(data any) ([]byte, error) {
buff := bytes.Buffer{} buff := bytes.Buffer{}
enc := gob.NewEncoder(&buff) enc := gob.NewEncoder(&buff)
err := enc.Encode(data) err := enc.Encode(data)
@ -42,7 +42,7 @@ func (g *GobEncoder) Encode(data interface{}) ([]byte, error) {
return buff.Bytes(), nil 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) buff := bytes.NewBuffer(encodeData)
dec := gob.NewDecoder(buff) dec := gob.NewDecoder(buff)
err := dec.Decode(decodeData) err := dec.Decode(decodeData)

View File

@ -49,7 +49,7 @@ type LongConnServer interface {
wsHandler(w http.ResponseWriter, r *http.Request) wsHandler(w http.ResponseWriter, r *http.Request)
GetUserAllCons(userID string) ([]*Client, bool) GetUserAllCons(userID string) ([]*Client, bool)
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
Validate(s interface{}) error Validate(s any) error
SetCacheHandler(cache cache.MsgModel) SetCacheHandler(cache cache.MsgModel)
SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry) SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry)
KickUserConn(client *Client) error KickUserConn(client *Client) error
@ -60,6 +60,12 @@ type LongConnServer interface {
MessageHandler MessageHandler
} }
var bufferPool = sync.Pool{
New: func() any {
return make([]byte, 1024)
},
}
type WsServer struct { type WsServer struct {
port int port int
wsMaxConnNum int64 wsMaxConnNum int64
@ -120,7 +126,7 @@ func (ws *WsServer) UnRegister(c *Client) {
ws.unregisterChan <- c ws.unregisterChan <- c
} }
func (ws *WsServer) Validate(s interface{}) error { func (ws *WsServer) Validate(s any) error {
//?question? //?question?
return nil return nil
} }
@ -145,7 +151,7 @@ func NewWsServer(opts ...Option) (*WsServer, error) {
writeBufferSize: config.writeBufferSize, writeBufferSize: config.writeBufferSize,
handshakeTimeout: config.handshakeTimeout, handshakeTimeout: config.handshakeTimeout,
clientPool: sync.Pool{ clientPool: sync.Pool{
New: func() interface{} { New: func() any {
return new(Client) return new(Client)
}, },
}, },

View File

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

View File

@ -61,7 +61,7 @@ type TriggerChannelValue struct {
type Cmd2Value struct { type Cmd2Value struct {
Cmd int Cmd int
Value interface{} Value any
} }
type ContextMsg struct { type ContextMsg struct {
message *sdkws.MsgData message *sdkws.MsgData

View File

@ -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
}

View File

@ -21,9 +21,9 @@ import (
) )
type Resp struct { type Resp struct {
Code int `json:"code"` Code int `json:"code"`
Msg string `json:"msg"` Msg string `json:"msg"`
Data interface{} `json:"data"` Data any `json:"data"`
} }
func (r *Resp) parseError() (err error) { func (r *Resp) parseError() (err error) {

View File

@ -159,7 +159,7 @@ func (g *Client) singlePush(ctx context.Context, token, userID string, pushReq P
return g.request(ctx, pushURL, pushReq, token, nil) 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} header := map[string]string{"token": token}
resp := &Resp{} resp := &Resp{}
resp.Data = output resp.Data = output
@ -170,7 +170,7 @@ func (g *Client) postReturn(
ctx context.Context, ctx context.Context,
url string, url string,
header map[string]string, header map[string]string,
input interface{}, input any,
output RespI, output RespI,
timeout int, timeout int,
) error { ) error {

View File

@ -23,7 +23,7 @@ const (
) )
type Audience struct { type Audience struct {
Object interface{} Object any
audience map[string][]string audience map[string][]string
} }

View File

@ -15,10 +15,10 @@
package body package body
type Message struct { type Message struct {
MsgContent string `json:"msg_content"` MsgContent string `json:"msg_content"`
Title string `json:"title,omitempty"` Title string `json:"title,omitempty"`
ContentType string `json:"content_type,omitempty"` ContentType string `json:"content_type,omitempty"`
Extras map[string]interface{} `json:"extras,omitempty"` Extras map[string]any `json:"extras,omitempty"`
} }
func (m *Message) SetMsgContent(c string) { func (m *Message) SetMsgContent(c string) {
@ -33,9 +33,9 @@ func (m *Message) SetContentType(c string) {
m.ContentType = c m.ContentType = c
} }
func (m *Message) SetExtras(key string, value interface{}) { func (m *Message) SetExtras(key string, value any) {
if m.Extras == nil { if m.Extras == nil {
m.Extras = make(map[string]interface{}) m.Extras = make(map[string]any)
} }
m.Extras[key] = value m.Extras[key] = value
} }

View File

@ -29,7 +29,7 @@ const (
) )
type Platform struct { type Platform struct {
Os interface{} Os any
osArry []string osArry []string
} }

View File

@ -15,11 +15,11 @@
package body package body
type PushObj struct { type PushObj struct {
Platform interface{} `json:"platform"` Platform any `json:"platform"`
Audience interface{} `json:"audience"` Audience any `json:"audience"`
Notification interface{} `json:"notification,omitempty"` Notification any `json:"notification,omitempty"`
Message interface{} `json:"message,omitempty"` Message any `json:"message,omitempty"`
Options interface{} `json:"options,omitempty"` Options any `json:"options,omitempty"`
} }
func (p *PushObj) SetPlatform(pf *Platform) { func (p *PushObj) SetPlatform(pf *Platform) {

View File

@ -69,11 +69,11 @@ func (j *JPush) Push(ctx context.Context, userIDs []string, title, content strin
pushObj.SetNotification(&no) pushObj.SetNotification(&no)
pushObj.SetMessage(&msg) pushObj.SetMessage(&msg)
pushObj.SetOptions(&opt) pushObj.SetOptions(&opt)
var resp interface{} var resp any
return j.request(ctx, pushObj, resp, 5) 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( return http2.PostReturn(
ctx, ctx,
config.Config.Push.Jpns.PushUrl, config.Config.Push.Jpns.PushUrl,

View File

@ -133,7 +133,7 @@ func (p *Pusher) Push2User(ctx context.Context, userIDs []string, msg *sdkws.Msg
return nil return nil
} }
func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t interface{}) error { func (p *Pusher) UnmarshalNotificationElem(bytes []byte, t any) error {
var notification sdkws.NotificationElem var notification sdkws.NotificationElem
if err := json.Unmarshal(bytes, &notification); err != nil { if err := json.Unmarshal(bytes, &notification); err != nil {
return err return err

View File

@ -16,6 +16,12 @@ package conversation
import ( import (
"context" "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" "google.golang.org/grpc"
@ -24,13 +30,11 @@ import (
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "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/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "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 { func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&tablerelation.ConversationModel{}); err != nil {
return err
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
} }
conversationDB := relation.NewConversationGorm(db) mongo, err := unrelation.NewMongo()
if err != nil {
return err
}
conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase())
if err != nil {
return err
}
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
pbconversation.RegisterConversationServer(server, &conversationServer{ pbconversation.RegisterConversationServer(server, &conversationServer{
conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient),
groupRpcClient: &groupRpcClient, groupRpcClient: &groupRpcClient,
conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewGorm(db)), conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())),
}) })
return nil return nil
} }
@ -145,7 +149,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
conversation.ConversationType = req.Conversation.ConversationType conversation.ConversationType = req.Conversation.ConversationType
conversation.UserID = req.Conversation.UserID conversation.UserID = req.Conversation.UserID
conversation.GroupID = req.Conversation.GroupID conversation.GroupID = req.Conversation.GroupID
m := make(map[string]interface{}) m := make(map[string]any)
if req.Conversation.RecvMsgOpt != nil { if req.Conversation.RecvMsgOpt != nil {
m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value m["recv_msg_opt"] = req.Conversation.RecvMsgOpt.Value
if req.Conversation.RecvMsgOpt.Value != conv.RecvMsgOpt { if req.Conversation.RecvMsgOpt.Value != conv.RecvMsgOpt {
@ -229,11 +233,12 @@ func (c *conversationServer) SetConversations(ctx context.Context,
// 获取超级大群开启免打扰的用户ID. // 获取超级大群开启免打扰的用户ID.
func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) { func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) {
userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) //userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID)
if err != nil { //if err != nil {
return nil, err // return nil, err
} //}
return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil //return &pbconversation.GetRecvMsgNotNotifyUserIDsResp{UserIDs: userIDs}, nil
return nil, errors.New("deprecated")
} }
// create conversation without notification for msg redis transfer. // 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) { func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID, 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 nil, err
} }
return &pbconversation.SetConversationMaxSeqResp{}, nil return &pbconversation.SetConversationMaxSeqResp{}, nil

View File

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

View File

@ -17,6 +17,8 @@ package friend
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
@ -32,13 +34,13 @@ import (
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
registry "github.com/OpenIMSDK/tools/discoveryregistry" registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/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" 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" "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 { func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB() // Initialize MongoDB
mongo, err := unrelation.NewMongo()
if err != nil { if err != nil {
return err return err
} }
if err := db.AutoMigrate(&tablerelation.FriendModel{}, &tablerelation.FriendRequestModel{}, &tablerelation.BlackModel{}); err != nil {
return err // Initialize Redis
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
} }
blackDB := relation.NewBlackGorm(db)
friendDB := relation.NewFriendGorm(db) friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase())
if err != nil {
return err
}
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) userRpcClient := rpcclient.NewUserRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
// Initialize notification sender
notificationSender := notification.NewFriendNotificationSender( notificationSender := notification.NewFriendNotificationSender(
&msgRpcClient, &msgRpcClient,
notification.WithRpcFunc(userRpcClient.GetUsersInfo), notification.WithRpcFunc(userRpcClient.GetUsersInfo),
) )
// Register Friend server with refactored MongoDB and Redis integrations
pbfriend.RegisterFriendServer(server, &friendServer{ pbfriend.RegisterFriendServer(server, &friendServer{
friendDatabase: controller.NewFriendDatabase( friendDatabase: controller.NewFriendDatabase(
friendDB, friendMongoDB,
relation.NewFriendRequestGorm(db), friendRequestMongoDB,
cache.NewFriendCacheRedis(rdb, friendDB, cache.GetDefaultOpt()), cache.NewFriendCacheRedis(rdb, friendMongoDB, cache.GetDefaultOpt()),
tx.NewGorm(db), tx.NewMongo(mongo.GetClient()),
), ),
blackDatabase: controller.NewBlackDatabase( blackDatabase: controller.NewBlackDatabase(
blackDB, blackMongoDB,
cache.NewBlackCacheRedis(rdb, blackDB, cache.GetDefaultOpt()), cache.NewBlackCacheRedis(rdb, blackMongoDB, cache.GetDefaultOpt()),
), ),
userRpcClient: &userRpcClient, userRpcClient: &userRpcClient,
notificationSender: notificationSender, notificationSender: notificationSender,
RegisterCenter: client, RegisterCenter: client,
conversationRpcClient: rpcclient.NewConversationRpcClient(client), conversationRpcClient: rpcclient.NewConversationRpcClient(client),
}) })
return nil return nil
} }
// ok. // ok.
func (s *friendServer) ApplyToAddFriend( func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) {
ctx context.Context,
req *pbfriend.ApplyToAddFriendReq,
) (resp *pbfriend.ApplyToAddFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.ApplyToAddFriendResp{} resp = &pbfriend.ApplyToAddFriendResp{}
if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.FromUserID); err != nil {
@ -127,10 +145,7 @@ func (s *friendServer) ApplyToAddFriend(
} }
// ok. // ok.
func (s *friendServer) ImportFriends( func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) {
ctx context.Context,
req *pbfriend.ImportFriendReq,
) (resp *pbfriend.ImportFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := authverify.CheckAdmin(ctx); err != nil { if err := authverify.CheckAdmin(ctx); err != nil {
return nil, err return nil, err
@ -165,10 +180,7 @@ func (s *friendServer) ImportFriends(
} }
// ok. // ok.
func (s *friendServer) RespondFriendApply( func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) {
ctx context.Context,
req *pbfriend.RespondFriendApplyReq,
) (resp *pbfriend.RespondFriendApplyResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.RespondFriendApplyResp{} resp = &pbfriend.RespondFriendApplyResp{}
if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil {
@ -204,10 +216,7 @@ func (s *friendServer) RespondFriendApply(
} }
// ok. // ok.
func (s *friendServer) DeleteFriend( func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) (resp *pbfriend.DeleteFriendResp, err error) {
ctx context.Context,
req *pbfriend.DeleteFriendReq,
) (resp *pbfriend.DeleteFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.DeleteFriendResp{} resp = &pbfriend.DeleteFriendResp{}
if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil { if err := s.userRpcClient.Access(ctx, req.OwnerUserID); err != nil {
@ -228,10 +237,7 @@ func (s *friendServer) DeleteFriend(
} }
// ok. // ok.
func (s *friendServer) SetFriendRemark( func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) {
ctx context.Context,
req *pbfriend.SetFriendRemarkReq,
) (resp *pbfriend.SetFriendRemarkResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue {
@ -256,10 +262,7 @@ func (s *friendServer) SetFriendRemark(
} }
// ok. // ok.
func (s *friendServer) GetDesignatedFriends( func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.GetDesignatedFriendsReq) (resp *pbfriend.GetDesignatedFriendsResp, err error) {
ctx context.Context,
req *pbfriend.GetDesignatedFriendsReq,
) (resp *pbfriend.GetDesignatedFriendsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetDesignatedFriendsResp{} resp = &pbfriend.GetDesignatedFriendsResp{}
if utils.Duplicate(req.FriendUserIDs) { if utils.Duplicate(req.FriendUserIDs) {
@ -290,15 +293,12 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
} }
// ok 获取接收到的好友申请(即别人主动申请的). // ok 获取接收到的好友申请(即别人主动申请的).
func (s *friendServer) GetPaginationFriendsApplyTo( func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyToReq,
) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friendRequests, total, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friendRequests, err := s.friendDatabase.PageFriendRequestToMe(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -312,16 +312,13 @@ func (s *friendServer) GetPaginationFriendsApplyTo(
} }
// ok 获取主动发出去的好友申请列表. // ok 获取主动发出去的好友申请列表.
func (s *friendServer) GetPaginationFriendsApplyFrom( func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsApplyFromReq,
) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetPaginationFriendsApplyFromResp{} resp = &pbfriend.GetPaginationFriendsApplyFromResp{}
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friendRequests, total, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friendRequests, err := s.friendDatabase.PageFriendRequestFromMe(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -334,10 +331,7 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(
} }
// ok. // ok.
func (s *friendServer) IsFriend( func (s *friendServer) IsFriend(ctx context.Context, req *pbfriend.IsFriendReq) (resp *pbfriend.IsFriendResp, err error) {
ctx context.Context,
req *pbfriend.IsFriendReq,
) (resp *pbfriend.IsFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.IsFriendResp{} resp = &pbfriend.IsFriendResp{}
resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2) resp.InUser1Friends, resp.InUser2Friends, err = s.friendDatabase.CheckIn(ctx, req.UserID1, req.UserID2)
@ -347,15 +341,12 @@ func (s *friendServer) IsFriend(
return resp, nil return resp, nil
} }
func (s *friendServer) GetPaginationFriends( func (s *friendServer) GetPaginationFriends(ctx context.Context, req *pbfriend.GetPaginationFriendsReq) (resp *pbfriend.GetPaginationFriendsResp, err error) {
ctx context.Context,
req *pbfriend.GetPaginationFriendsReq,
) (resp *pbfriend.GetPaginationFriendsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err
} }
friends, total, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination.PageNumber, req.Pagination.ShowNumber) total, friends, err := s.friendDatabase.PageOwnerFriends(ctx, req.UserID, req.Pagination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -368,10 +359,7 @@ func (s *friendServer) GetPaginationFriends(
return resp, nil return resp, nil
} }
func (s *friendServer) GetFriendIDs( func (s *friendServer) GetFriendIDs(ctx context.Context, req *pbfriend.GetFriendIDsReq) (resp *pbfriend.GetFriendIDsResp, err error) {
ctx context.Context,
req *pbfriend.GetFriendIDsReq,
) (resp *pbfriend.GetFriendIDsResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
return nil, err return nil, err

View File

@ -26,7 +26,7 @@ func (s *groupServer) GetGroupInfoCache(
ctx context.Context, ctx context.Context,
req *pbgroup.GetGroupInfoCacheReq, req *pbgroup.GetGroupInfoCacheReq,
) (resp *pbgroup.GetGroupInfoCacheResp, err error) { ) (resp *pbgroup.GetGroupInfoCacheResp, err error) {
group, err := s.GroupDatabase.TakeGroup(ctx, req.GroupID) group, err := s.db.TakeGroup(ctx, req.GroupID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -38,7 +38,7 @@ func (s *groupServer) GetGroupMemberCache(
ctx context.Context, ctx context.Context,
req *pbgroup.GetGroupMemberCacheReq, req *pbgroup.GetGroupMemberCacheReq,
) (resp *pbgroup.GetGroupMemberCacheResp, err error) { ) (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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -27,7 +27,7 @@ import (
func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any {
m := make(map[string]any) m := make(map[string]any)
if group.GroupName != "" { if group.GroupName != "" {
m["name"] = group.GroupName m["group_name"] = group.GroupName
} }
if group.Notification != "" { if group.Notification != "" {
m["notification"] = group.Notification m["notification"] = group.Notification

View File

@ -17,119 +17,9 @@ package group
import ( import (
"context" "context"
"github.com/OpenIMSDK/tools/utils"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
func (s *groupServer) FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) { func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMemberModel) error {
members, err := s.GroupDatabase.FindGroupMember(ctx, groupIDs, userIDs, roleLevels) return s.Notification.PopulateGroupMember(ctx, members...)
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
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,16 +26,16 @@ func (s *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCrea
if req.Start > req.End { if req.Start > req.End {
return nil, errs.ErrArgs.Wrap("start > 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 { if err != nil {
return nil, err return nil, err
} }
start := time.UnixMilli(req.Start) start := time.UnixMilli(req.Start)
before, err := s.GroupDatabase.CountTotal(ctx, &start) before, err := s.db.CountTotal(ctx, &start)
if err != nil { if err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -16,99 +16,15 @@ package group
import ( import (
"context" "context"
"fmt" "errors"
"strings"
"github.com/OpenIMSDK/protocol/constant"
pbgroup "github.com/OpenIMSDK/protocol/group" 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( func (s *groupServer) GetJoinedSuperGroupList(context.Context, *pbgroup.GetJoinedSuperGroupListReq) (*pbgroup.GetJoinedSuperGroupListResp, error) {
ctx context.Context, return nil, errors.New("deprecated")
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) GetSuperGroupsInfo( func (s *groupServer) GetSuperGroupsInfo(context.Context, *pbgroup.GetSuperGroupsInfoReq) (resp *pbgroup.GetSuperGroupsInfoResp, err error) {
ctx context.Context, return nil, errors.New("deprecated")
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
} }

View File

@ -15,12 +15,11 @@
package msg package msg
import ( import (
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils" "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" "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 { func IsNotFound(err error) bool {
switch utils.Unwrap(err) { switch utils.Unwrap(err) {
case redis.Nil, gorm.ErrRecordNotFound: case redis.Nil, mongo.ErrNoDocuments:
return true return true
default: default:
return false return false

View File

@ -32,11 +32,11 @@ func genLogID() string {
} }
func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) { func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq) (*third.UploadLogsResp, error) {
var DBlogs []*relationtb.Log var DBlogs []*relationtb.LogModel
userID := ctx.Value(constant.OpUserID).(string) userID := ctx.Value(constant.OpUserID).(string)
platform := constant.PlatformID2Name[int(req.Platform)] platform := constant.PlatformID2Name[int(req.Platform)]
for _, fileURL := range req.FileURLs { for _, fileURL := range req.FileURLs {
log := relationtb.Log{ log := relationtb.LogModel{
Version: req.Version, Version: req.Version,
SystemType: req.SystemType, SystemType: req.SystemType,
Platform: platform, Platform: platform,
@ -57,7 +57,7 @@ func (t *thirdServer) UploadLogs(ctx context.Context, req *third.UploadLogsReq)
} }
} }
if log.LogID == "" { if log.LogID == "" {
return nil, errs.ErrData.Wrap("Log id gen error") return nil, errs.ErrData.Wrap("LogModel id gen error")
} }
DBlogs = append(DBlogs, &log) DBlogs = append(DBlogs, &log)
} }
@ -92,8 +92,8 @@ func (t *thirdServer) DeleteLogs(ctx context.Context, req *third.DeleteLogsReq)
return &third.DeleteLogsResp{}, nil return &third.DeleteLogsResp{}, nil
} }
func dbToPbLogInfos(logs []*relationtb.Log) []*third.LogInfo { func dbToPbLogInfos(logs []*relationtb.LogModel) []*third.LogInfo {
db2pbForLogInfo := func(log *relationtb.Log) *third.LogInfo { db2pbForLogInfo := func(log *relationtb.LogModel) *third.LogInfo {
return &third.LogInfo{ return &third.LogInfo{
Filename: log.FileName, Filename: log.FileName,
UserID: log.UserID, UserID: log.UserID,
@ -120,7 +120,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
if req.StartTime > req.EndTime { if req.StartTime > req.EndTime {
return nil, errs.ErrArgs.Wrap("startTime>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 { if err != nil {
return nil, err return nil, err
} }
@ -128,18 +128,16 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
for _, log := range logs { for _, log := range logs {
userIDs = append(userIDs, log.UserID) userIDs = append(userIDs, log.UserID)
} }
users, err := t.thirdDatabase.FindUsers(ctx, userIDs) userMap, err := t.userRpcClient.GetUsersInfoMap(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
IDtoName := make(map[string]string)
for _, user := range users {
IDtoName[user.UserID] = user.Nickname
}
for _, pbLog := range pbLogs { for _, pbLog := range pbLogs {
pbLog.Nickname = IDtoName[pbLog.UserID] if user, ok := userMap[pbLog.UserID]; ok {
pbLog.Nickname = user.Nickname
}
} }
resp.LogsInfos = pbLogs resp.LogsInfos = pbLogs
resp.Total = total resp.Total = uint32(total)
return &resp, nil return &resp, nil
} }

View File

@ -64,7 +64,7 @@ func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.In
Key: haErr.Object.Key, Key: haErr.Object.Key,
Size: haErr.Object.Size, Size: haErr.Object.Size,
ContentType: req.ContentType, ContentType: req.ContentType,
Cause: req.Cause, Group: req.Cause,
CreateTime: time.Now(), CreateTime: time.Now(),
} }
if err := t.s3dataBase.SetObject(ctx, obj); err != nil { 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, Key: result.Key,
Size: result.Size, Size: result.Size,
ContentType: req.ContentType, ContentType: req.ContentType,
Cause: req.Cause, Group: req.Cause,
CreateTime: time.Now(), CreateTime: time.Now(),
} }
if err := t.s3dataBase.SetObject(ctx, obj); err != nil { if err := t.s3dataBase.SetObject(ctx, obj); err != nil {

View File

@ -17,15 +17,17 @@ package third
import ( import (
"context" "context"
"fmt" "fmt"
"net/url" "net/url"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/kodo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/protocol/third"
@ -34,13 +36,22 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { 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 apiURL := config.Config.Object.ApiURL
if apiURL == "" { if apiURL == "" {
return fmt.Errorf("api url is empty") return fmt.Errorf("api url is empty")
@ -56,13 +67,6 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if err != nil { if err != nil {
return err return err
} }
db, err := relation.NewGormDB()
if err != nil {
return err
}
if err := db.AutoMigrate(&relationtb.ObjectModel{}); err != nil {
return err
}
// 根据配置文件策略选择 oss 方式 // 根据配置文件策略选择 oss 方式
enable := config.Config.Object.Enable enable := config.Config.Object.Enable
var o s3.Interface var o s3.Interface
@ -73,25 +77,17 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
o, err = cos.NewCos() o, err = cos.NewCos()
case "oss": case "oss":
o, err = oss.NewOSS() o, err = oss.NewOSS()
case "kodo":
o, err = kodo.NewKodo()
default: default:
err = fmt.Errorf("invalid object enable: %s", enable) err = fmt.Errorf("invalid object enable: %s", enable)
} }
if err != nil { if err != nil {
return err return err
} }
//specialerror.AddErrHandler(func(err error) errs.CodeError {
// if o.IsNotFound(err) {
// return errs.ErrRecordNotFound
// }
// return nil
//})
third.RegisterThirdServer(server, &thirdServer{ third.RegisterThirdServer(server, &thirdServer{
apiURL: apiURL, apiURL: apiURL,
thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), db), thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb),
userRpcClient: rpcclient.NewUserRpcClient(client), userRpcClient: rpcclient.NewUserRpcClient(client),
s3dataBase: controller.NewS3Database(rdb, o, relation.NewObjectInfo(db)), s3dataBase: controller.NewS3Database(rdb, o, s3db),
defaultExpire: time.Hour * 24 * 7, defaultExpire: time.Hour * 24 * 7,
}) })
return nil return nil

View File

@ -20,11 +20,14 @@ import (
"strings" "strings"
"time" "time"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "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/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "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/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "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 { func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
db, err := relation.NewGormDB()
if err != nil {
return err
}
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis()
if err != nil { if err != nil {
return err return err
@ -67,9 +65,6 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
if err != nil { if err != nil {
return err return err
} }
if err := db.AutoMigrate(&tablerelation.UserModel{}); err != nil {
return err
}
users := make([]*tablerelation.UserModel, 0) users := make([]*tablerelation.UserModel, 0)
if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) { if len(config.Config.Manager.UserID) != len(config.Config.Manager.Nickname) {
return errors.New("len(config.Config.Manager.AppManagerUid) != 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 { for k, v := range config.Config.Manager.UserID {
users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin}) users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.Manager.Nickname[k], AppMangerLevel: constant.AppAdmin})
} }
userDB := relation.NewUserGorm(db) userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
if err != nil {
return err
}
cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
database := controller.NewUserDatabase(userDB, cache, tx.NewGorm(db), userMongoDB) database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client)
@ -118,12 +116,8 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI
if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil {
return nil, err return nil, err
} }
user := convert.UserPb2DB(req.UserInfo) data := convert.UserPb2DBMap(req.UserInfo)
if err != nil { if err := s.UpdateByMap(ctx, req.UserInfo.UserID, data); err != nil {
return nil, err
}
err = s.Update(ctx, user)
if err != nil {
return nil, err return nil, err
} }
_ = s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserInfo.UserID) _ = 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 { if _, err := s.FindWithError(ctx, []string{req.UserID}); err != nil {
return nil, err return nil, err
} }
m := make(map[string]interface{}, 1) m := make(map[string]any, 1)
m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt m["global_recv_msg_opt"] = req.GlobalRecvMsgOpt
if err := s.UpdateByMap(ctx, req.UserID, m); err != nil { if err := s.UpdateByMap(ctx, req.UserID, m); err != nil {
return nil, err return nil, err
@ -175,7 +169,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR
if err != nil { if err != nil {
return nil, err return nil, err
} }
userIDs := make(map[string]interface{}, 0) userIDs := make(map[string]any, 0)
for _, v := range users { for _, v := range users {
userIDs[v.UserID] = nil 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) { func (s *userServer) GetPaginationUsers(ctx context.Context, req *pbuser.GetPaginationUsersReq) (resp *pbuser.GetPaginationUsersResp, err error) {
var pageNumber, showNumber int32 total, users, err := s.Page(ctx, req.Pagination)
if req.Pagination != nil {
pageNumber = req.Pagination.PageNumber
showNumber = req.Pagination.ShowNumber
}
users, total, err := s.Page(ctx, pageNumber, showNumber)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -269,11 +258,11 @@ func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Ge
// GetAllUserID Get user account by page. // GetAllUserID Get user account by page.
func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) { 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 { if err != nil {
return nil, err 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. // SubscribeOrCancelUsersStatus Subscribe online or cancel online users.

View File

@ -19,6 +19,8 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@ -91,7 +93,11 @@ func (c *MsgTool) ConversationsDestructMsgs() {
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
pageNumber := rand.Int63() % maxPage 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 { if err != nil {
log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
continue continue
@ -133,7 +139,7 @@ func (c *MsgTool) ConversationsDestructMsgs() {
continue continue
} }
if len(seqs) > 0 { 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) log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue continue
} }

View File

@ -19,6 +19,11 @@ import (
"fmt" "fmt"
"math" "math"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
@ -31,13 +36,11 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
@ -72,33 +75,45 @@ func InitMsgTool() (*MsgTool, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
db, err := relation.NewGormDB()
if err != nil {
return nil, err
}
discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) 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()))*/
if err != nil { if err != nil {
return nil, err return nil, err
} }
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()))
userDB := relation.NewUserGorm(db) userDB, err := mgo.NewUserMongo(mongo.GetDatabase())
if err != nil {
return nil, err
}
msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase())
ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase( userDatabase := controller.NewUserDatabase(
userDB, userDB,
cache.NewUserCacheRedis(rdb, relation.NewUserGorm(db), cache.GetDefaultOpt()), cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()),
tx.NewGorm(db), ctxTx,
userMongoDB, 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( conversationDatabase := controller.NewConversationDatabase(
relation.NewConversationGorm(db), conversationDB,
cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), relation.NewConversationGorm(db)), cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB),
tx.NewGorm(db), ctxTx,
) )
msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgRpcClient := rpcclient.NewMessageRpcClient(discov)
msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient))
@ -144,7 +159,11 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() {
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
pageNumber := rand.Int63() % maxPage 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 { if err != nil {
log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber) log.ZError(ctx, "PageConversationIDs failed", err, "pageNumber", pageNumber)
continue continue

View File

@ -32,7 +32,7 @@ func (c *MsgTool) convertTools() {
for _, conversationID := range conversationIDs { for _, conversationID := range conversationIDs {
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID)) conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID))
} }
userIDs, err := c.userDatabase.GetAllUserID(ctx, 0, 0) _, userIDs, err := c.userDatabase.GetAllUserID(ctx, nil)
if err != nil { if err != nil {
log.ZError(ctx, "get all user ids failed", err) log.ZError(ctx, "get all user ids failed", err)
return return

View File

@ -36,7 +36,7 @@ type SendMsg struct {
SenderPlatformID int32 `json:"senderPlatformID"` SenderPlatformID int32 `json:"senderPlatformID"`
// Content is the actual content of the message, required and excluded from Swagger documentation. // 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 is an integer that represents the type of the content.
ContentType int32 `json:"contentType" binding:"required"` ContentType int32 `json:"contentType" binding:"required"`

View File

@ -28,7 +28,7 @@ import (
) )
func Secret() jwt.Keyfunc { func Secret() jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) { return func(token *jwt.Token) (any, error) {
return []byte(config.Config.Secret), nil 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))) 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()) return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret())
} }

View File

@ -46,15 +46,13 @@ func (a *RpcCmd) Exec() error {
return a.Execute() return a.Execute()
} }
func (a *RpcCmd) StartSvr( func (a *RpcCmd) StartSvr(name string, rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error {
name string,
rpcFn func(discov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error,
) error {
if a.GetPortFlag() == 0 { if a.GetPortFlag() == 0 {
return errors.New("port is required") return errors.New("port is required")
} }
return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn) return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn)
} }
func (a *RpcCmd) GetPortFromConfig(portType string) int { func (a *RpcCmd) GetPortFromConfig(portType string) int {
switch a.Name { switch a.Name {
case RpcPushServer: case RpcPushServer:

View File

@ -44,6 +44,18 @@ type POfflinePush struct {
Ext string `yaml:"ext"` 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 { type configStruct struct {
Envs struct { Envs struct {
Discovery string `yaml:"discovery"` Discovery string `yaml:"discovery"`
@ -55,17 +67,7 @@ type configStruct struct {
Password string `yaml:"password"` Password string `yaml:"password"`
} `yaml:"zookeeper"` } `yaml:"zookeeper"`
Mysql struct { Mysql *MYSQL `yaml:"mysql"`
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"`
Mongo struct { Mongo struct {
Uri string `yaml:"uri"` Uri string `yaml:"uri"`

View File

@ -71,7 +71,7 @@ func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options {
return opts return opts
} }
func initConfig(config interface{}, configName, configFolderPath string) error { func initConfig(config any, configName, configFolderPath string) error {
configFolderPath = filepath.Join(configFolderPath, configName) configFolderPath = filepath.Join(configFolderPath, configName)
_, err := os.Stat(configFolderPath) _, err := os.Stat(configFolderPath)
if err != nil { if err != nil {

View File

@ -76,7 +76,7 @@ func TestGetOptionsByNotification(t *testing.T) {
func Test_initConfig(t *testing.T) { func Test_initConfig(t *testing.T) {
type args struct { type args struct {
config interface{} config any
configName string configName string
configFolderPath string configFolderPath string
} }

View File

@ -16,6 +16,7 @@ package convert
import ( import (
"context" "context"
"fmt"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
@ -31,23 +32,22 @@ func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel {
return dbFriend return dbFriend
} }
func FriendDB2Pb( func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel,
ctx context.Context,
friendDB *relation.FriendModel,
getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error), getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
) (*sdkws.FriendInfo, error) { ) (*sdkws.FriendInfo, error) {
pbfriend := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}}
utils.CopyStructFields(pbfriend, friendDB)
users, err := getUsers(ctx, []string{friendDB.FriendUserID}) users, err := getUsers(ctx, []string{friendDB.FriendUserID})
if err != nil { if err != nil {
return nil, err return nil, err
} }
pbfriend.FriendUser.UserID = users[friendDB.FriendUserID].UserID user, ok := users[friendDB.FriendUserID]
pbfriend.FriendUser.Nickname = users[friendDB.FriendUserID].Nickname if !ok {
pbfriend.FriendUser.FaceURL = users[friendDB.FriendUserID].FaceURL return nil, fmt.Errorf("user not found: %s", friendDB.FriendUserID)
pbfriend.FriendUser.Ex = users[friendDB.FriendUserID].Ex }
pbfriend.CreateTime = friendDB.CreateTime.Unix()
return pbfriend, nil return &sdkws.FriendInfo{
FriendUser: user,
CreateTime: friendDB.CreateTime.Unix(),
}, nil
} }
func FriendsDB2Pb( func FriendsDB2Pb(
@ -118,3 +118,37 @@ func FriendRequestDB2Pb(
} }
return res, nil 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
}

View File

@ -16,32 +16,58 @@ package convert
import ( import (
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"time"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
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 { for _, user := range users {
var userPb sdkws.UserInfo userPb := &sdkws.UserInfo{
userPb.UserID = user.UserID UserID: user.UserID,
userPb.Nickname = user.Nickname Nickname: user.Nickname,
userPb.FaceURL = user.FaceURL FaceURL: user.FaceURL,
userPb.Ex = user.Ex Ex: user.Ex,
userPb.CreateTime = user.CreateTime.UnixMilli() CreateTime: user.CreateTime.UnixMilli(),
userPb.AppMangerLevel = user.AppMangerLevel AppMangerLevel: user.AppMangerLevel,
userPb.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt GlobalRecvMsgOpt: user.GlobalRecvMsgOpt,
result = append(result, &userPb) }
result = append(result, userPb)
} }
return result return result
} }
func UserPb2DB(user *sdkws.UserInfo) *relationtb.UserModel { func UserPb2DB(user *sdkws.UserInfo) *relationtb.UserModel {
var userDB relationtb.UserModel return &relationtb.UserModel{
userDB.UserID = user.UserID UserID: user.UserID,
userDB.Nickname = user.Nickname Nickname: user.Nickname,
userDB.FaceURL = user.FaceURL FaceURL: user.FaceURL,
userDB.Ex = user.Ex Ex: user.Ex,
userDB.AppMangerLevel = user.AppMangerLevel CreateTime: time.UnixMilli(user.CreateTime),
userDB.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt AppMangerLevel: user.AppMangerLevel,
return &userDB 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
} }

View File

@ -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)
}
}

View File

@ -26,7 +26,6 @@ import (
"github.com/OpenIMSDK/tools/utils" "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" 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) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error)
DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache
// get one super group recv msg but do not notification userID list // 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 DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache
// get one super group recv msg but do not notification userID list hash // 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 DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache
//GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
@ -101,20 +100,20 @@ type ConversationRedisCache struct {
expireTime time.Duration expireTime time.Duration
} }
func NewNewConversationRedis( //func NewNewConversationRedis(
rdb redis.UniversalClient, // rdb redis.UniversalClient,
conversationDB *relation.ConversationGorm, // conversationDB *relation.ConversationGorm,
options rockscache.Options, // options rockscache.Options,
) ConversationCache { //) ConversationCache {
rcClient := rockscache.NewClient(rdb, options) // rcClient := rockscache.NewClient(rdb, options)
//
return &ConversationRedisCache{ // return &ConversationRedisCache{
rcClient: rcClient, // rcClient: rcClient,
metaCache: NewMetaCacheRedis(rcClient), // metaCache: NewMetaCacheRedis(rcClient),
conversationDB: conversationDB, // conversationDB: conversationDB,
expireTime: conversationExpireTime, // expireTime: conversationExpireTime,
} // }
} //}
func (c *ConversationRedisCache) NewCache() ConversationCache { func (c *ConversationRedisCache) NewCache() ConversationCache {
return &ConversationRedisCache{ 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) { //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 getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) {
return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) // return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
}) // })
} //}
func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache { func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache {
keys := make([]string, 0, len(ownerUserIDs)) keys := make([]string, 0, len(ownerUserIDs))
@ -313,19 +312,19 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID st
return cache return cache
} }
func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) { //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) { // return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) {
userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) // userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
if err != nil { // if err != nil {
return 0, err // return 0, err
} // }
utils.Sort(userIDs, true) // utils.Sort(userIDs, true)
bi := big.NewInt(0) // bi := big.NewInt(0)
bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16) // bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16)
return bi.Uint64(), nil // return bi.Uint64(), nil
}, // },
) // )
} //}
func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache { func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache {
cache := c.NewCache() cache := c.NewCache()

View File

@ -33,19 +33,20 @@ const (
friendKey = "FRIEND_INFO:" friendKey = "FRIEND_INFO:"
) )
// args fn will exec when no data in msgCache. // FriendCache is an interface for caching friend-related data.
type FriendCache interface { type FriendCache interface {
metaCache metaCache
NewCache() FriendCache NewCache() FriendCache
GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error)
// call when friendID List changed // Called when friendID list changed
DelFriendIDs(ownerUserID ...string) FriendCache 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) 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 DelFriend(ownerUserID, friendUserID string) FriendCache
} }
// FriendCacheRedis is an implementation of the FriendCache interface using Redis.
type FriendCacheRedis struct { type FriendCacheRedis struct {
metaCache metaCache
friendDB relationtb.FriendModelInterface friendDB relationtb.FriendModelInterface
@ -53,6 +54,7 @@ type FriendCacheRedis struct {
rcClient *rockscache.Client rcClient *rockscache.Client
} }
// NewFriendCacheRedis creates a new instance of FriendCacheRedis.
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface, func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface,
options rockscache.Options) FriendCache { options rockscache.Options) FriendCache {
rcClient := rockscache.NewClient(rdb, options) 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 { func (f *FriendCacheRedis) NewCache() FriendCache {
return &FriendCacheRedis{ return &FriendCacheRedis{
rcClient: f.rcClient, 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 { func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string {
return friendIDsKey + ownerUserID return friendIDsKey + ownerUserID
} }
// getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache.
func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string { func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string {
return TwoWayFriendsIDsKey + ownerUserID return TwoWayFriendsIDsKey + ownerUserID
} }
// getFriendKey returns the key for storing friend info in the cache.
func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string { func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string {
return friendKey + ownerUserID + "-" + friendUserID 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) { 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 getCache(ctx, f.rcClient, f.getFriendIDsKey(ownerUserID), f.expireTime, func(ctx context.Context) ([]string, error) {
return f.friendDB.FindFriendUserIDs(ctx, ownerUserID) return f.friendDB.FindFriendUserIDs(ctx, ownerUserID)
}) })
} }
// DelFriendIDs deletes friend IDs from the cache.
func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache { func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache {
newGroupCache := f.NewCache() newGroupCache := f.NewCache()
keys := make([]string, 0, len(ownerUserIDs)) keys := make([]string, 0, len(ownerUserIDs))
@ -102,7 +110,7 @@ func (f *FriendCacheRedis) DelFriendIDs(ownerUserIDs ...string) FriendCache {
return newGroupCache 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) { func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID string) (twoWayFriendIDs []string, err error) {
friendIDs, err := f.GetFriendIDs(ctx, ownerUserID) friendIDs, err := f.GetFriendIDs(ctx, ownerUserID)
if err != nil { if err != nil {
@ -121,6 +129,7 @@ func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID s
return twoWayFriendIDs, nil return twoWayFriendIDs, nil
} }
// DelTwoWayFriendIDs deletes two-way friend IDs from the cache.
func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) FriendCache { func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) FriendCache {
newFriendCache := f.NewCache() newFriendCache := f.NewCache()
newFriendCache.AddKeys(f.getTwoWayFriendsIDsKey(ownerUserID)) newFriendCache.AddKeys(f.getTwoWayFriendsIDsKey(ownerUserID))
@ -128,14 +137,15 @@ func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID s
return newFriendCache return newFriendCache
} }
func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, // GetFriend retrieves friend info from the cache or the database if not found.
friendUserID string) (friend *relationtb.FriendModel, err error) { func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationtb.FriendModel, err error) {
return getCache(ctx, f.rcClient, f.getFriendKey(ownerUserID, return getCache(ctx, f.rcClient, f.getFriendKey(ownerUserID,
friendUserID), f.expireTime, func(ctx context.Context) (*relationtb.FriendModel, error) { friendUserID), f.expireTime, func(ctx context.Context) (*relationtb.FriendModel, error) {
return f.friendDB.Take(ctx, ownerUserID, friendUserID) return f.friendDB.Take(ctx, ownerUserID, friendUserID)
}) })
} }
// DelFriend deletes friend info from the cache.
func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) FriendCache { func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) FriendCache {
newFriendCache := f.NewCache() newFriendCache := f.NewCache()
newFriendCache.AddKeys(f.getFriendKey(ownerUserID, friendUserID)) newFriendCache.AddKeys(f.getFriendKey(ownerUserID, friendUserID))

View File

@ -16,8 +16,13 @@ package cache
import ( import (
"context" "context"
"fmt"
"strconv"
"time" "time"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/dtm-labs/rockscache" "github.com/dtm-labs/rockscache"
@ -26,21 +31,24 @@ import (
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
) )
const ( const (
groupExpireTime = time.Second * 60 * 60 * 12 groupExpireTime = time.Second * 60 * 60 * 12
groupInfoKey = "GROUP_INFO:" groupInfoKey = "GROUP_INFO:"
groupMemberIDsKey = "GROUP_MEMBER_IDS:" groupMemberIDsKey = "GROUP_MEMBER_IDS:"
groupMembersHashKey = "GROUP_MEMBERS_HASH2:" groupMembersHashKey = "GROUP_MEMBERS_HASH2:"
groupMemberInfoKey = "GROUP_MEMBER_INFO:" groupMemberInfoKey = "GROUP_MEMBER_INFO:"
joinedSuperGroupsKey = "JOIN_SUPER_GROUPS:" //groupOwnerInfoKey = "GROUP_OWNER_INFO:"
SuperGroupMemberIDsKey = "SUPER_GROUP_MEMBER_IDS:" joinedGroupsKey = "JOIN_GROUPS_KEY:"
joinedGroupsKey = "JOIN_GROUPS_KEY:" groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
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 { type GroupCache interface {
metaCache metaCache
NewCache() GroupCache NewCache() GroupCache
@ -48,11 +56,6 @@ type GroupCache interface {
GetGroupInfo(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) GetGroupInfo(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error)
DelGroupsInfo(groupIDs ...string) GroupCache 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) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error)
GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error)
DelGroupMembersHash(groupID string) GroupCache DelGroupMembersHash(groupID string) GroupCache
@ -69,9 +72,16 @@ type GroupCache interface {
GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*relationtb.GroupMemberModel, err error) GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*relationtb.GroupMemberModel, err error)
GetAllGroupMembersInfo(ctx context.Context, groupID 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) 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 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) GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error)
DelGroupsMemberNum(groupID ...string) GroupCache DelGroupsMemberNum(groupID ...string) GroupCache
} }
@ -81,10 +91,9 @@ type GroupCacheRedis struct {
groupDB relationtb.GroupModelInterface groupDB relationtb.GroupModelInterface
groupMemberDB relationtb.GroupMemberModelInterface groupMemberDB relationtb.GroupMemberModelInterface
groupRequestDB relationtb.GroupRequestModelInterface groupRequestDB relationtb.GroupRequestModelInterface
mongoDB unrelationtb.SuperGroupModelInterface
expireTime time.Duration expireTime time.Duration
rcClient *rockscache.Client rcClient *rockscache.Client
hashCode func(ctx context.Context, groupID string) (uint64, error) groupHash GroupHash
} }
func NewGroupCacheRedis( func NewGroupCacheRedis(
@ -92,8 +101,7 @@ func NewGroupCacheRedis(
groupDB relationtb.GroupModelInterface, groupDB relationtb.GroupModelInterface,
groupMemberDB relationtb.GroupMemberModelInterface, groupMemberDB relationtb.GroupMemberModelInterface,
groupRequestDB relationtb.GroupRequestModelInterface, groupRequestDB relationtb.GroupRequestModelInterface,
mongoClient unrelationtb.SuperGroupModelInterface, hashCode GroupHash,
hashCode func(ctx context.Context, groupID string) (uint64, error),
opts rockscache.Options, opts rockscache.Options,
) GroupCache { ) GroupCache {
rcClient := rockscache.NewClient(rdb, opts) rcClient := rockscache.NewClient(rdb, opts)
@ -101,8 +109,7 @@ func NewGroupCacheRedis(
return &GroupCacheRedis{ return &GroupCacheRedis{
rcClient: rcClient, expireTime: groupExpireTime, rcClient: rcClient, expireTime: groupExpireTime,
groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB, groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB,
mongoDB: mongoClient, groupHash: hashCode,
hashCode: hashCode,
metaCache: NewMetaCacheRedis(rcClient), metaCache: NewMetaCacheRedis(rcClient),
} }
} }
@ -114,7 +121,6 @@ func (g *GroupCacheRedis) NewCache() GroupCache {
groupDB: g.groupDB, groupDB: g.groupDB,
groupMemberDB: g.groupMemberDB, groupMemberDB: g.groupMemberDB,
groupRequestDB: g.groupRequestDB, groupRequestDB: g.groupRequestDB,
mongoDB: g.mongoDB,
metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...), metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...),
} }
} }
@ -123,18 +129,10 @@ func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
return groupInfoKey + groupID return groupInfoKey + groupID
} }
func (g *GroupCacheRedis) getJoinedSuperGroupsIDKey(userID string) string {
return joinedSuperGroupsKey + userID
}
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string { func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
return joinedGroupsKey + userID return joinedGroupsKey + userID
} }
func (g *GroupCacheRedis) getSuperGroupMemberIDsKey(groupID string) string {
return SuperGroupMemberIDsKey + groupID
}
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string { func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
return groupMembersHashKey + groupID return groupMembersHashKey + groupID
} }
@ -151,6 +149,10 @@ func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
return groupMemberNumKey + groupID 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) { func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {
key := g.getGroupInfoKey(group.GroupID) key := g.getGroupInfoKey(group.GroupID)
for i, _key := range keys { for i, _key := range keys {
@ -173,15 +175,7 @@ func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *relationtb.GroupMembe
return 0, errIndex return 0, errIndex
} }
// / groupInfo.
func (g *GroupCacheRedis) GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error) { 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 batchGetCache2(ctx, g.rcClient, g.expireTime, groupIDs, func(groupID string) string {
return g.getGroupInfoKey(groupID) return g.getGroupInfoKey(groupID)
}, func(ctx context.Context, groupID string) (*relationtb.GroupModel, error) { }, func(ctx context.Context, groupID string) (*relationtb.GroupModel, error) {
@ -206,123 +200,44 @@ func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) GroupCache {
return newGroupCache return newGroupCache
} }
func (g *GroupCacheRedis) GetJoinedSuperGroupIDs(ctx context.Context, userID string) (joinedSuperGroupIDs []string, err error) { func (g *GroupCacheRedis) DelGroupsOwner(groupIDs ...string) GroupCache {
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 {
newGroupCache := g.NewCache()
keys := make([]string, 0, len(userIDs))
for _, userID := range userIDs {
keys = append(keys, g.getJoinedSuperGroupsIDKey(userID))
}
newGroupCache.AddKeys(keys...)
return newGroupCache
}
func (g *GroupCacheRedis) DelSuperGroupMemberIDs(groupIDs ...string) GroupCache {
newGroupCache := g.NewCache() newGroupCache := g.NewCache()
keys := make([]string, 0, len(groupIDs)) keys := make([]string, 0, len(groupIDs))
for _, groupID := range groupIDs { for _, groupID := range groupIDs {
keys = append(keys, g.getSuperGroupMemberIDsKey(groupID)) keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, constant.GroupOwner))
} }
newGroupCache.AddKeys(keys...) newGroupCache.AddKeys(keys...)
return newGroupCache return newGroupCache
} }
// groupMembersHash. func (g *GroupCacheRedis) DelGroupRoleLevel(groupID string, roleLevels []int32) GroupCache {
func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) { newGroupCache := g.NewCache()
return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) { keys := make([]string, 0, len(roleLevels))
return g.hashCode(ctx, groupID) for _, roleLevel := range roleLevels {
}) keys = append(keys, g.getGroupRoleLevelMemberIDsKey(groupID, roleLevel))
}
newGroupCache.AddKeys(keys...)
return newGroupCache
}
//return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) GroupCache {
// func(ctx context.Context) (uint64, error) { return g.DelGroupRoleLevel(groupID, []int32{constant.GroupOwner, constant.GroupAdmin, constant.GroupOrdinaryUsers})
// userIDs, err := g.GetGroupMemberIDs(ctx, groupID) }
// if err != nil {
// return 0, err func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) {
// } if g.groupHash == nil {
// log.ZInfo(ctx, "GetGroupMembersHash", "groupID", groupID, "userIDs", userIDs) return 0, errs.ErrInternalServer.Wrap("group hash is nil")
// var members []*relationtb.GroupMemberModel }
// if len(userIDs) > 0 { return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) {
// members, err = g.GetGroupMembersInfo(ctx, groupID, userIDs) return g.groupHash.GetGroupHash(ctx, groupID)
// 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) { 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) res := make(map[string]*relationtb.GroupSimpleUserID)
for _, groupID := range groupIDs { for _, groupID := range groupIDs {
hash, err := g.GetGroupMembersHash(ctx, groupID) hash, err := g.GetGroupMembersHash(ctx, groupID)
@ -347,7 +262,6 @@ func (g *GroupCacheRedis) DelGroupMembersHash(groupID string) GroupCache {
return cache return cache
} }
// groupMemberIDs.
func (g *GroupCacheRedis) GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error) { 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 getCache(ctx, g.rcClient, g.getGroupMemberIDsKey(groupID), g.expireTime, func(ctx context.Context) ([]string, error) {
return g.groupMemberDB.FindMemberUserID(ctx, groupID) 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) { 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 batchGetCache2(ctx, g.rcClient, g.expireTime, userIDs, func(userID string) string {
return g.getGroupMemberInfoKey(groupID, userID) return g.getGroupMemberInfoKey(groupID, userID)
}, func(ctx context.Context, userID string) (*relationtb.GroupMemberModel, error) { }, 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 { if err != nil {
return nil, err 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) return g.GetGroupMembersInfo(ctx, groupID, groupMemberIDs)
} }
@ -483,3 +383,68 @@ func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) GroupCache {
return cache 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)
})
}

View File

@ -38,7 +38,7 @@ const (
var errIndex = errors.New("err index") var errIndex = errors.New("err index")
type metaCache interface { type metaCache interface {
ExecDel(ctx context.Context) error ExecDel(ctx context.Context, distinct ...bool) error
// delete key rapid // delete key rapid
DelKey(ctx context.Context, key string) error DelKey(ctx context.Context, key string) error
AddKeys(keys ...string) AddKeys(keys ...string)
@ -57,7 +57,10 @@ type metaCacheRedis struct {
retryInterval time.Duration 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 { if len(m.keys) > 0 {
log.ZDebug(ctx, "delete cache", "keys", m.keys) log.ZDebug(ctx, "delete cache", "keys", m.keys)
for _, key := range m.keys { for _, key := range m.keys {

View File

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

View File

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

View File

@ -14,8 +14,8 @@ import (
type ObjectCache interface { type ObjectCache interface {
metaCache metaCache
GetName(ctx context.Context, name string) (*relationtb.ObjectModel, error) GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error)
DelObjectName(names ...string) ObjectCache DelObjectName(engine string, names ...string) ObjectCache
} }
func NewObjectCacheRedis(rdb redis.UniversalClient, objDB relationtb.ObjectInfoModelInterface) 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() objectCache := g.NewCache()
keys := make([]string, 0, len(names)) keys := make([]string, 0, len(names))
for _, name := range names { for _, name := range names {
keys = append(keys, g.getObjectKey(name)) keys = append(keys, g.getObjectKey(name, engine))
} }
objectCache.AddKeys(keys...) objectCache.AddKeys(keys...)
return objectCache return objectCache
} }
func (g *objectCacheRedis) getObjectKey(name string) string { func (g *objectCacheRedis) getObjectKey(engine string, name string) string {
return "OBJECT:" + name return "OBJECT:" + engine + ":" + name
} }
func (g *objectCacheRedis) GetName(ctx context.Context, name string) (*relationtb.ObjectModel, error) { func (g *objectCacheRedis) GetName(ctx context.Context, engine string, name string) (*relationtb.ObjectModel, error) {
return getCache(ctx, g.rcClient, g.getObjectKey(name), g.expireTime, func(ctx context.Context) (*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, name) return g.objDB.Take(ctx, engine, name)
}) })
} }

View File

@ -22,6 +22,8 @@ import (
"strconv" "strconv"
"time" "time"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
@ -31,8 +33,6 @@ import (
"github.com/dtm-labs/rockscache" "github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
const ( const (
@ -59,7 +59,8 @@ type UserCache interface {
type UserCacheRedis struct { type UserCacheRedis struct {
metaCache metaCache
rdb redis.UniversalClient rdb redis.UniversalClient
//userDB relationtb.UserModelInterface
userDB relationtb.UserModelInterface userDB relationtb.UserModelInterface
expireTime time.Duration expireTime time.Duration
rcClient *rockscache.Client 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) { func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) {
return getCache( return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) {
ctx, return u.userDB.Take(ctx, userID)
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) { 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 batchGetCache2(ctx, u.rcClient, u.expireTime, userIDs, func(userID string) string {
return u.getUserInfoKey(userID) return u.getUserInfoKey(userID)
}, func(ctx context.Context, userID string) (*relationtb.UserModel, error) { }, 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)) UserIDNum := crc32.ChecksumIEEE([]byte(userID))
modKey := strconv.Itoa(int(UserIDNum % statusMod)) modKey := strconv.Itoa(int(UserIDNum % statusMod))
key := olineStatusKey + modKey key := olineStatusKey + modKey
log.ZDebug(ctx, "SetUserStatus args", "userID", userID, "status", status, log.ZDebug(ctx, "SetUserStatus args", "userID", userID, "status", status, "platformID", platformID, "modKey", modKey, "key", key)
"platformID", platformID, "modKey", modKey, "key", key)
isNewKey, err := u.rdb.Exists(ctx, key).Result() isNewKey, err := u.rdb.Exists(ctx, key).Result()
if err != nil { if err != nil {
return errs.Wrap(err) return errs.Wrap(err)

View File

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

View File

@ -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)
}

View File

@ -18,6 +18,8 @@ import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
@ -31,7 +33,7 @@ import (
type ConversationDatabase interface { type ConversationDatabase interface {
// UpdateUserConversationFiled 更新用户该会话的属性信息 // 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 创建一批新的会话
CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error
// SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作 // SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作
@ -39,26 +41,26 @@ type ConversationDatabase interface {
// FindConversations 根据会话ID获取某个用户的多个会话 // FindConversations 根据会话ID获取某个用户的多个会话
FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error)
// FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID // FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID
FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) //FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
// GetUserAllConversation 获取一个用户在服务器上所有的会话 // GetUserAllConversation 获取一个用户在服务器上所有的会话
GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error) GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error)
// SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性 // SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性
SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error
// SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作 // 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 CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error
GetConversationIDs(ctx context.Context, userID string) ([]string, error) GetConversationIDs(ctx context.Context, userID string) ([]string, error)
GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error)
GetAllConversationIDs(ctx context.Context) ([]string, error) GetAllConversationIDs(ctx context.Context) ([]string, error)
GetAllConversationIDsNumber(ctx context.Context) (int64, error) GetAllConversationIDsNumber(ctx context.Context) (int64, error)
PageConversationIDs(ctx context.Context, 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) //GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error)
GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error) GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error)
GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, 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{ return &conversationDatabase{
conversationDB: conversation, conversationDB: conversation,
cache: cache, cache: cache,
@ -69,22 +71,21 @@ func NewConversationDatabase(conversation relationtb.ConversationModelInterface,
type conversationDatabase struct { type conversationDatabase struct {
conversationDB relationtb.ConversationModelInterface conversationDB relationtb.ConversationModelInterface
cache cache.ConversationCache 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) { func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) (err error) {
cache := c.cache.NewCache() return c.tx.Transaction(ctx, func(ctx context.Context) error {
if conversation.GroupID != "" { cache := c.cache.NewCache()
cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(conversation.GroupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(conversation.GroupID) 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 := c.conversationDB.FindUserID(ctx, userIDs, []string{conversation.ConversationID})
haveUserIDs, err := conversationTx.FindUserID(ctx, userIDs, []string{conversation.ConversationID})
if err != nil { if err != nil {
return err return err
} }
if len(haveUserIDs) > 0 { if len(haveUserIDs) > 0 {
_, err = conversationTx.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap) _, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap)
if err != nil { if err != nil {
return err return err
} }
@ -112,20 +113,17 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context,
conversations = append(conversations, temp) conversations = append(conversations, temp)
} }
if len(conversations) > 0 { if len(conversations) > 0 {
err = conversationTx.Create(ctx, conversations) err = c.conversationDB.Create(ctx, conversations)
if err != nil { if err != nil {
return err return err
} }
cache = cache.DelConversationIDs(NotUserIDs...).DelUserConversationIDsHash(NotUserIDs...).DelConversations(conversation.ConversationID, NotUserIDs...) cache = cache.DelConversationIDs(NotUserIDs...).DelUserConversationIDsHash(NotUserIDs...).DelConversations(conversation.ConversationID, NotUserIDs...)
} }
return nil return cache.ExecDel(ctx)
}); err != nil { })
return err
}
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) _, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args)
if err != nil { if err != nil {
return err 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 { func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Context, conversations []*relationtb.ConversationModel) error {
cache := c.cache.NewCache() return c.tx.Transaction(ctx, func(ctx context.Context) error {
if err := c.tx.Transaction(func(tx any) error { cache := c.cache.NewCache()
conversationTx := c.conversationDB.NewTx(tx)
for _, conversation := range conversations { for _, conversation := range conversations {
for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} { for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} {
ownerUserID := v[0] ownerUserID := v[0]
userID := v[1] 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 { if err != nil {
return err return err
} }
if len(haveUserIDs) > 0 { 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 { if err != nil {
return err return err
} }
@ -176,18 +173,15 @@ func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Con
newConversation.UserID = userID newConversation.UserID = userID
newConversation.ConversationID = conversation.ConversationID newConversation.ConversationID = conversation.ConversationID
newConversation.IsPrivateChat = conversation.IsPrivateChat 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 return err
} }
cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID) cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID)
} }
} }
} }
return nil return cache.ExecDel(ctx)
}); err != nil { })
return err
}
return cache.ExecDel(ctx)
} }
func (c *conversationDatabase) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) { 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 { func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error {
cache := c.cache.NewCache() 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) { groupIDs := utils.Distinct(utils.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) {
return e.GroupID, e.GroupID != "" return e.GroupID, e.GroupID != ""
})) }))
for _, groupID := range groupIDs { for _, groupID := range groupIDs {
cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(groupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID) cache = cache.DelSuperGroupRecvMsgNotNotifyUserIDs(groupID).DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID)
} }
if err := c.tx.Transaction(func(tx any) error {
var conversationIDs []string var conversationIDs []string
for _, conversation := range conversations { for _, conversation := range conversations {
conversationIDs = append(conversationIDs, conversation.ConversationID) conversationIDs = append(conversationIDs, conversation.ConversationID)
cache = cache.DelConversations(conversation.OwnerUserID, conversation.ConversationID) cache = cache.DelConversations(conversation.OwnerUserID, conversation.ConversationID)
} }
conversationTx := c.conversationDB.NewTx(tx) existConversations, err := c.conversationDB.Find(ctx, ownerUserID, conversationIDs)
existConversations, err := conversationTx.Find(ctx, ownerUserID, conversationIDs)
if err != nil { if err != nil {
return err return err
} }
if len(existConversations) > 0 { if len(existConversations) > 0 {
for _, conversation := range conversations { for _, conversation := range conversations {
err = conversationTx.Update(ctx, conversation) err = c.conversationDB.Update(ctx, conversation)
if err != nil { if err != nil {
return err return err
} }
@ -246,23 +238,22 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs
if err != nil { if err != nil {
return err return err
} }
cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID).DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...) cache = cache.DelConversationIDs(ownerUserID).
DelUserConversationIDsHash(ownerUserID).
DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...)
} }
return nil return cache.ExecDel(ctx)
}); err != nil { })
return err
}
return cache.ExecDel(ctx)
} }
func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) { //func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID) // return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
} //}
func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error { func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error {
cache := c.cache.NewCache() return c.tx.Transaction(ctx, func(ctx context.Context) error {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID) cache := c.cache.NewCache()
if err := c.tx.Transaction(func(tx any) error { conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID)
existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID}) existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID})
if err != nil { if err != nil {
return err return err
@ -281,18 +272,15 @@ func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context,
return err 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 { if err != nil {
return err return err
} }
for _, v := range existConversationUserIDs { for _, v := range existConversationUserIDs {
cache = cache.DelConversations(v, conversationID) cache = cache.DelConversations(v, conversationID)
} }
return nil return c.cache.ExecDel(ctx)
}); err != nil { })
return err
}
return cache.ExecDel(ctx)
} }
func (c *conversationDatabase) GetConversationIDs(ctx context.Context, userID string) ([]string, error) { 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) return c.conversationDB.GetAllConversationIDsNumber(ctx)
} }
func (c *conversationDatabase) PageConversationIDs(ctx context.Context, pageNumber, showNumber int32) ([]string, error) { func (c *conversationDatabase) PageConversationIDs(ctx context.Context, pagination pagination.Pagination) ([]string, error) {
return c.conversationDB.PageConversationIDs(ctx, pageNumber, showNumber) 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) { func (c *conversationDatabase) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error) {
return c.conversationDB.GetConversationsByConversationID(ctx, conversationIDs) return c.conversationDB.GetConversationsByConversationID(ctx, conversationIDs)
} }

View File

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

View File

@ -16,23 +16,18 @@ package controller
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
"github.com/dtm-labs/rockscache" "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/protocol/constant"
"github.com/OpenIMSDK/tools/tx" "github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "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/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" 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 { type GroupDatabase interface {
@ -40,23 +35,26 @@ type GroupDatabase interface {
CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error
TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error)
FindGroup(ctx context.Context, groupIDs []string) (groups []*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, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error)
SearchGroup(ctx context.Context, keyword string, pageNumber, showNumber int32) (uint32, []*relationtb.GroupModel, error)
UpdateGroup(ctx context.Context, groupID string, data map[string]any) error UpdateGroup(ctx context.Context, groupID string, data map[string]any) error
DismissGroup(ctx context.Context, groupID string, deleteMember bool) 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) TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error)
TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, 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) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error)
FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error)
FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err 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) PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error)
PageGetGroupMember(ctx context.Context, groupID string, pageNumber, showNumber int32) (total uint32, 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, groupIDs []string, userIDs []string, roleLevels []int32, pageNumber, showNumber int32) (uint32, []*relationtb.GroupMemberModel, 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 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 DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error
MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error)
@ -67,15 +65,8 @@ type GroupDatabase interface {
// GroupRequest // GroupRequest
CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error
TakeGroupRequest(ctx context.Context, groupID string, userID string) (*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) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error)
PageGroupRequestUser(ctx context.Context, userID string, pageNumber, showNumber int32) (uint32, []*relationtb.GroupRequestModel, error) PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*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
// 获取群总数 // 获取群总数
CountTotal(ctx context.Context, before *time.Time) (count int64, err error) CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
@ -85,61 +76,91 @@ type GroupDatabase interface {
} }
func NewGroupDatabase( func NewGroupDatabase(
group relationtb.GroupModelInterface, rdb redis.UniversalClient,
member relationtb.GroupMemberModelInterface, groupDB relationtb.GroupModelInterface,
request relationtb.GroupRequestModelInterface, groupMemberDB relationtb.GroupMemberModelInterface,
tx tx.Tx, groupRequestDB relationtb.GroupRequestModelInterface,
ctxTx tx.CtxTx, ctxTx tx.CtxTx,
superGroup unrelationtb.SuperGroupModelInterface, groupHash cache.GroupHash,
cache cache.GroupCache,
) GroupDatabase { ) 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 := rockscache.NewDefaultOptions()
rcOptions.StrongConsistency = true rcOptions.StrongConsistency = true
rcOptions.RandomExpireAdjustment = 0.2 rcOptions.RandomExpireAdjustment = 0.2
return NewGroupDatabase( return &groupDatabase{
relation.NewGroupDB(db), groupDB: groupDB,
relation.NewGroupMemberDB(db), groupMemberDB: groupMemberDB,
relation.NewGroupRequest(db), groupRequestDB: groupRequestDB,
tx.NewGorm(db), ctxTx: ctxTx,
tx.NewMongo(database.Client()), cache: cache.NewGroupCacheRedis(rdb, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions),
unrelation.NewSuperGroupMongoDriver(database), }
cache.NewGroupCacheRedis(
rdb,
relation.NewGroupDB(db),
relation.NewGroupMemberDB(db),
relation.NewGroupRequest(db),
unrelation.NewSuperGroupMongoDriver(database),
hashCode,
rcOptions,
),
)
} }
type groupDatabase struct { type groupDatabase struct {
groupDB relationtb.GroupModelInterface groupDB relationtb.GroupModelInterface
groupMemberDB relationtb.GroupMemberModelInterface groupMemberDB relationtb.GroupMemberModelInterface
groupRequestDB relationtb.GroupRequestModelInterface groupRequestDB relationtb.GroupRequestModelInterface
tx tx.Tx
ctxTx tx.CtxTx ctxTx tx.CtxTx
cache cache.GroupCache cache cache.GroupCache
mongoDB unrelationtb.SuperGroupModelInterface
} }
func (g *groupDatabase) GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) { func (g *groupDatabase) FindGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupMemberModel, error) {
return g.groupDB.GetGroupIDsByGroupType(ctx, groupType) return g.cache.GetGroupMembersInfo(ctx, groupID, userIDs)
}
func (g *groupDatabase) FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*relationtb.GroupMemberModel, error) {
return g.cache.FindGroupMemberUser(ctx, groupIDs, userID)
}
func (g *groupDatabase) FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) ([]*relationtb.GroupMemberModel, error) {
return g.cache.GetGroupRolesLevelMemberInfo(ctx, groupID, roleLevels)
}
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.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.Create(ctx, groupMembers); err != nil {
return err
}
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)
}
}
return c.ExecDel(ctx, true)
})
} }
func (g *groupDatabase) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) { func (g *groupDatabase) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) {
@ -154,57 +175,16 @@ func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string)
return uint32(num), nil return uint32(num), nil
} }
func (g *groupDatabase) CreateGroup( func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (*relationtb.GroupModel, error) {
ctx context.Context,
groups []*relationtb.GroupModel,
groupMembers []*relationtb.GroupMemberModel,
) error {
cache := g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
if len(groups) > 0 {
if err := g.groupDB.NewTx(tx).Create(ctx, groups); err != nil {
return err
}
}
if len(groupMembers) > 0 {
if err := g.groupMemberDB.NewTx(tx).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)
}
cache = cache.DelJoinedGroupID(groupMember.UserID).DelGroupMembersInfo(groupMember.GroupID, groupMember.UserID)
}
cache = cache.DelGroupsInfo(createGroupIDs...)
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error) {
return g.cache.GetGroupInfo(ctx, groupID) 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) return g.cache.GetGroupsInfo(ctx, groupIDs)
} }
func (g *groupDatabase) SearchGroup( func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error) {
ctx context.Context, return g.groupDB.Search(ctx, keyword, pagination)
keyword string,
pageNumber, showNumber int32,
) (uint32, []*relationtb.GroupModel, error) {
return g.groupDB.Search(ctx, keyword, pageNumber, showNumber)
} }
func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data map[string]any) error { 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 { func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error {
cache := g.cache.NewCache() return g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
if err := g.tx.Transaction(func(tx any) error { c := g.cache.NewCache()
if err := g.groupDB.NewTx(tx).UpdateStatus(ctx, groupID, constant.GroupStatusDismissed); err != nil { if err := g.groupDB.UpdateState(ctx, groupID, constant.GroupStatusDismissed); err != nil {
return err return err
} }
if deleteMember { if deleteMember {
if err := g.groupMemberDB.NewTx(tx).DeleteGroup(ctx, []string{groupID}); err != nil {
return err
}
userIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID) userIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID)
if err != nil { if err != nil {
return err 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 c.DelGroupsInfo(groupID).ExecDel(ctx)
return nil })
}); err != nil {
return err
}
return cache.ExecDel(ctx)
} }
func (g *groupDatabase) TakeGroupMember( func (g *groupDatabase) TakeGroupMember(ctx context.Context, groupID string, userID string) (*relationtb.GroupMemberModel, error) {
ctx context.Context,
groupID string,
userID string,
) (groupMember *relationtb.GroupMemberModel, err error) {
return g.cache.GetGroupMemberInfo(ctx, groupID, userID) return g.cache.GetGroupMemberInfo(ctx, groupID, userID)
} }
func (g *groupDatabase) TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error) { 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) { func (g *groupDatabase) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
return g.groupMemberDB.FindUserManagedGroupID(ctx, userID) return g.groupMemberDB.FindUserManagedGroupID(ctx, userID)
} }
func (g *groupDatabase) PageGroupRequest( func (g *groupDatabase) PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) {
ctx context.Context, return g.groupRequestDB.PageGroup(ctx, groupIDs, pagination)
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) { func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, 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) PageGetJoinGroup(
ctx context.Context,
userID string,
pageNumber, showNumber int32,
) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) {
groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID) groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID)
if err != nil { if err != nil {
return 0, nil, err 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}) groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, []string{userID})
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
totalGroupMembers = append(totalGroupMembers, groupMembers...) totalGroupMembers = append(totalGroupMembers, groupMembers...)
} }
return uint32(len(groupIDs)), totalGroupMembers, nil return int64(len(groupIDs)), totalGroupMembers, nil
} }
func (g *groupDatabase) PageGetGroupMember( func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error) {
ctx context.Context,
groupID string,
pageNumber, showNumber int32,
) (total uint32, totalGroupMembers []*relationtb.GroupMemberModel, err error) {
groupMemberIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID) groupMemberIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID)
if err != nil { if err != nil {
return 0, nil, err 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 { if len(pageIDs) == 0 {
return uint32(len(groupMemberIDs)), nil, nil return int64(len(groupMemberIDs)), nil, nil
} }
members, err := g.cache.GetGroupMembersInfo(ctx, groupID, pageIDs) members, err := g.cache.GetGroupMembersInfo(ctx, groupID, pageIDs)
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
} }
return uint32(len(groupMemberIDs)), members, nil return int64(len(groupMemberIDs)), members, nil
} }
func (g *groupDatabase) SearchGroupMember( func (g *groupDatabase) SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error) {
ctx context.Context, return g.groupMemberDB.SearchMember(ctx, keyword, groupID, pagination)
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) HandlerGroupRequest( func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error {
ctx context.Context, return g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
groupID string, if err := g.groupRequestDB.UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
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 {
return err return err
} }
if member != nil { 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 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 return err
} }
} }
@ -391,13 +302,11 @@ func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, u
DelGroupsMemberNum(groupID). DelGroupsMemberNum(groupID).
DelJoinedGroupID(userIDs...). DelJoinedGroupID(userIDs...).
DelGroupMembersInfo(groupID, userIDs...). DelGroupMembersInfo(groupID, userIDs...).
DelGroupAllRoleLevel(groupID).
ExecDel(ctx) ExecDel(ctx)
} }
func (g *groupDatabase) MapGroupMemberUserID( func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error) {
ctx context.Context,
groupIDs []string,
) (map[string]*relationtb.GroupSimpleUserID, error) {
return g.cache.GetGroupMemberHashMap(ctx, groupIDs) 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 { func (g *groupDatabase) TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error {
return g.tx.Transaction(func(tx any) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
rowsAffected, err := g.groupMemberDB.NewTx(tx).UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel) if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel); err != nil {
if err != nil {
return err return err
} }
if rowsAffected != 1 { if err := g.groupMemberDB.UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner); err != nil {
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 {
return err return err
} }
if rowsAffected != 1 { return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID).
return utils.Wrap(fmt.Errorf("newOwnerUserID %s rowsAffected = %d", newOwnerUserID, rowsAffected), "") DelGroupAllRoleLevel(groupID).
} DelGroupMembersHash(groupID).ExecDel(ctx)
return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID).DelGroupMembersHash(groupID).ExecDel(ctx)
}) })
} }
func (g *groupDatabase) UpdateGroupMember( func (g *groupDatabase) UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error {
ctx context.Context,
groupID string,
userID string,
data map[string]any,
) error {
if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil { if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil {
return err 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 { func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error {
cache := g.cache.NewCache() return g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
if err := g.tx.Transaction(func(tx any) error { c := g.cache.NewCache()
for _, item := range data { 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 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 return c.ExecDel(ctx, true)
}); err != nil { })
return err
}
return cache.ExecDel(ctx)
} }
func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error { func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error {
return g.tx.Transaction(func(tx any) error { return g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
db := g.groupRequestDB.NewTx(tx)
for _, request := range requests { 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 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) return g.groupRequestDB.Take(ctx, groupID, userID)
} }
func (g *groupDatabase) PageGroupRequestUser( func (g *groupDatabase) PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error) {
ctx context.Context, return g.groupRequestDB.Page(ctx, userID, pagination)
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) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { 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) 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) 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 { func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error {
if len(groupIDs) == 0 { if len(groupIDs) == 0 {
return nil return nil
@ -566,6 +406,5 @@ func (g *groupDatabase) DeleteGroupMemberHash(ctx context.Context, groupIDs []st
for _, groupID := range groupIDs { for _, groupID := range groupIDs {
c = c.DelGroupMembersHash(groupID) c = c.DelGroupMembersHash(groupID)
} }
return c.ExecDel(ctx) return c.ExecDel(ctx)
} }

View File

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

View File

@ -235,7 +235,7 @@ func Test_FindBySeq(t *testing.T) {
func TestName(t *testing.T) { func TestName(t *testing.T) {
db := GetDB() db := GetDB()
var seqs []int64 var seqs []int64
for i := int64(1); i <= 4; i++ { for i := int64(1); i <= 50; i++ {
seqs = append(seqs, i) seqs = append(seqs, i)
} }
msgs, err := db.getMsgBySeqsRange(context.Background(), "4931176757", "si_3866692501_4931176757", seqs, seqs[0], seqs[len(seqs)-1]) msgs, err := db.getMsgBySeqsRange(context.Background(), "4931176757", "si_3866692501_4931176757", seqs, seqs[0], seqs[len(seqs)-1])

View File

@ -72,14 +72,15 @@ func (s *s3Database) CompleteMultipartUpload(ctx context.Context, uploadID strin
} }
func (s *s3Database) SetObject(ctx context.Context, info *relation.ObjectModel) error { 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 { if err := s.db.SetObject(ctx, info); err != nil {
return err 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) { 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 { if err != nil {
return time.Time{}, "", err return time.Time{}, "", err
} }

View File

@ -18,10 +18,9 @@ import (
"context" "context"
"time" "time"
"gorm.io/gorm" "github.com/OpenIMSDK/tools/pagination"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
dbimpl "github.com/openimsdk/open-im-server/v3/pkg/common/db/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/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 FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error
SetAppBadge(ctx context.Context, userID string, value int) error SetAppBadge(ctx context.Context, userID string, value int) error
// about log for debug // about log for debug
UploadLogs(ctx context.Context, logs []*relation.Log) error UploadLogs(ctx context.Context, logs []*relation.LogModel) error
DeleteLogs(ctx context.Context, logID []string, userID string) error DeleteLogs(ctx context.Context, logID []string, userID string) error
SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*relation.Log, error) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error)
GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.Log, error) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error)
FindUsers(ctx context.Context, userIDs []string) ([]*relation.UserModel, error)
} }
type thirdDatabase struct { type thirdDatabase struct {
cache cache.MsgModel cache cache.MsgModel
logdb relation.LogInterface 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)
} }
// DeleteLogs implements ThirdDatabase. // DeleteLogs implements ThirdDatabase.
@ -53,22 +45,22 @@ func (t *thirdDatabase) DeleteLogs(ctx context.Context, logID []string, userID s
} }
// GetLogs implements ThirdDatabase. // GetLogs implements ThirdDatabase.
func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.Log, error) { func (t *thirdDatabase) GetLogs(ctx context.Context, LogIDs []string, userID string) ([]*relation.LogModel, error) {
return t.logdb.Get(ctx, LogIDs, userID) return t.logdb.Get(ctx, LogIDs, userID)
} }
// SearchLogs implements ThirdDatabase. // SearchLogs implements ThirdDatabase.
func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pageNumber int32, showNumber int32) (uint32, []*relation.Log, error) { func (t *thirdDatabase) SearchLogs(ctx context.Context, keyword string, start time.Time, end time.Time, pagination pagination.Pagination) (int64, []*relation.LogModel, error) {
return t.logdb.Search(ctx, keyword, start, end, pageNumber, showNumber) return t.logdb.Search(ctx, keyword, start, end, pagination)
} }
// UploadLogs implements ThirdDatabase. // UploadLogs implements ThirdDatabase.
func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.Log) error { func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.LogModel) error {
return t.logdb.Create(ctx, logs) return t.logdb.Create(ctx, logs)
} }
func NewThirdDatabase(cache cache.MsgModel, db *gorm.DB) ThirdDatabase { func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDatabase {
return &thirdDatabase{cache: cache, logdb: dbimpl.NewLogGorm(db), userdb: dbimpl.NewUserGorm(db)} return &thirdDatabase{cache: cache, logdb: logdb}
} }
func (t *thirdDatabase) FcmUpdateToken( func (t *thirdDatabase) FcmUpdateToken(

View File

@ -18,16 +18,19 @@ import (
"context" "context"
"time" "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" "github.com/OpenIMSDK/protocol/user"
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
type UserDatabase interface { 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 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) Create(ctx context.Context, users []*relation.UserModel) (err error)
// Update update (non-zero value) external guarantee userID exists // 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 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 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 true as long as one exists
IsExist(ctx context.Context, userIDs []string) (exist bool, err error) IsExist(ctx context.Context, userIDs []string) (exist bool, err error)
// GetAllUserID Get all user IDs // 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 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) InitOnce(ctx context.Context, users []*relation.UserModel) (err error)
// CountTotal Get the total number of users // CountTotal Get the total number of users
@ -68,28 +71,40 @@ type UserDatabase interface {
} }
type userDatabase struct { type userDatabase struct {
tx tx.CtxTx
userDB relation.UserModelInterface userDB relation.UserModelInterface
cache cache.UserCache cache cache.UserCache
tx tx.Tx
mongoDB unrelationtb.UserModelInterface 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} 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 { userIDs := utils.Slice(users, func(e *relation.UserModel) string {
return e.UserID 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 { if err != nil {
return err return err
} }
miss := utils.SliceAnySub(users, result, func(e *relation.UserModel) string { return e.UserID })
if len(miss) > 0 { // Determine which users are missing from the database.
_ = u.userDB.Create(ctx, miss) 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 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. // 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) { func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
users, err = u.cache.GetUsersInfo(ctx, userIDs) return u.cache.GetUsersInfo(ctx, userIDs)
return
} }
// Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db. // 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) { func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) (err error) {
if err := u.tx.Transaction(func(tx any) error { return u.tx.Transaction(ctx, func(ctx context.Context) error {
err = u.userDB.Create(ctx, users) if err = u.userDB.Create(ctx, users); err != nil {
if err != nil {
return err return err
} }
return nil return u.cache.DelUsersInfo(utils.Slice(users, func(e *relation.UserModel) string {
}); err != nil { return e.UserID
return err })...).ExecDel(ctx)
} })
var userIDs []string
for _, user := range users {
userIDs = append(userIDs, user.UserID)
}
return u.cache.DelUsersInfo(userIDs...).ExecDel(ctx)
} }
// Update (non-zero value) externally guarantees that userID exists. //// Update (non-zero value) externally guarantees that userID exists.
func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) { //func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) {
if err := u.userDB.Update(ctx, user); err != nil { // if err := u.userDB.Update(ctx, user); err != nil {
return err // return err
} // }
return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx) // return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx)
} //}
// UpdateByMap update (zero value) externally guarantees that userID exists. // UpdateByMap update (zero value) externally guarantees that userID exists.
func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) { func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) {
if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil { return u.tx.Transaction(ctx, func(ctx context.Context) error {
return err if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil {
} return err
return u.cache.DelUsersInfo(userID).ExecDel(ctx) }
return u.cache.DelUsersInfo(userID).ExecDel(ctx)
})
} }
// Page Gets, returns no error if not found. // Page Gets, returns no error if not found.
func (u *userDatabase) Page( func (u *userDatabase) Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) {
ctx context.Context, return u.userDB.Page(ctx, pagination)
pageNumber, showNumber int32,
) (users []*relation.UserModel, count int64, err error) {
return u.userDB.Page(ctx, pageNumber, showNumber)
} }
// IsExist Does userIDs exist? As long as there is one, it will be true. // 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. // GetAllUserID Get all user IDs.
func (u *userDatabase) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) { func (u *userDatabase) GetAllUserID(ctx context.Context, pagination pagination.Pagination) (total int64, userIDs []string, err error) {
return u.userDB.GetAllUserID(ctx, pageNumber, showNumber) return u.userDB.GetAllUserID(ctx, pagination)
} }
// CountTotal Get the total number of users. // CountTotal Get the total number of users.

View File

@ -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}))
}

View File

@ -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}),
)
}

131
pkg/common/db/mgo/friend.go Normal file
View File

@ -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}))
}

View File

@ -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)
}

105
pkg/common/db/mgo/group.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

70
pkg/common/db/mgo/log.go Normal file
View File

@ -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})
}

View File

@ -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})
}

113
pkg/common/db/mgo/user.go Normal file
View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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,
)
}

View File

@ -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"

View File

@ -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,
"",
)
}

View File

@ -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
}

View File

@ -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,
"",
)
}

View File

@ -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, "")
}

View File

@ -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())
}

View File

@ -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}
}

View File

@ -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
}

View File

@ -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 }

View File

@ -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)
}

View File

@ -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
}

View File

@ -46,6 +46,10 @@ type Controller struct {
impl s3.Interface impl s3.Interface
} }
func (c *Controller) Engine() string {
return c.impl.Engine()
}
func (c *Controller) HashPath(md5 string) string { func (c *Controller) HashPath(md5 string) string {
return path.Join(hashPath, md5) return path.Join(hashPath, md5)
} }

View File

@ -10,4 +10,4 @@ import (
) )
//go:linkname newRequest github.com/tencentyun/cos-go-sdk-v5.(*Client).newRequest //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)

View File

@ -1 +0,0 @@
package kodo

View File

@ -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
}

View File

@ -26,7 +26,7 @@ import (
func signHeader(c oss.Conn, req *http.Request, canonicalizedResource string) func signHeader(c oss.Conn, req *http.Request, canonicalizedResource string)
//go:linkname getURLParams github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.getURLParams //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 //go:linkname getURL github.com/aliyun/aliyun-oss-go-sdk/oss.urlMaker.getURL
func getURL(um urlMaker, bucket, object, params string) *url.URL func getURL(um urlMaker, bucket, object, params string) *url.URL

0
pkg/common/db/s3/oss/oss.go Executable file → Normal file
View File

View File

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

View File

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

View File

@ -17,62 +17,43 @@ package relation
import ( import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
) )
const ( // FriendModel represents the data structure for a friend relationship in MongoDB.
FriendModelTableName = "friends"
)
type FriendModel struct { type FriendModel struct {
OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` OwnerUserID string `bson:"owner_user_id"`
FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"` FriendUserID string `bson:"friend_user_id"`
Remark string `gorm:"column:remark;size:255"` Remark string `bson:"remark"`
CreateTime time.Time `gorm:"column:create_time;autoCreateTime"` CreateTime time.Time `bson:"create_time"`
AddSource int32 `gorm:"column:add_source"` AddSource int32 `bson:"add_source"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"` OperatorUserID string `bson:"operator_user_id"`
Ex string `gorm:"column:ex;size:1024"` Ex string `bson:"ex"`
}
func (FriendModel) TableName() string {
return FriendModelTableName
} }
// FriendModelInterface defines the operations for managing friends in MongoDB.
type FriendModelInterface interface { type FriendModelInterface interface {
// 插入多条记录 // Create inserts multiple friend records.
Create(ctx context.Context, friends []*FriendModel) (err error) 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) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error)
// 更新ownerUserID单个好友信息 更新零值 // UpdateByMap updates specific fields of a friend document using a map.
UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error) UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]any) (err error)
// 更新好友信息的非零值 // UpdateRemark modify remarks.
Update(ctx context.Context, friends []*FriendModel) (err error)
// 更新好友备注(也支持零值
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
// 获取单个好友信息,如没找到 返回错误 // Take retrieves a single friend document. Returns an error if not found.
Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error) 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) 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) FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error)
// 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在也不返回错误 // FindReversalFriends finds users who have added the specified user as a friend.
FindReversalFriends( FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) (friends []*FriendModel, err error)
ctx context.Context, // FindOwnerFriends retrieves a paginated list of friends for a given owner.
friendUserID string, FindOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error)
ownerUserIDs []string, // FindInWhoseFriends finds users who have added the specified user as a friend, with pagination.
) (friends []*FriendModel, err error) FindInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*FriendModel, err error)
// 获取ownerUserID好友列表 支持翻页 // FindFriendUserIDs retrieves a list of friend user IDs for a given owner.
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) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
NewTx(tx any) FriendModelInterface
} }

View File

@ -17,50 +17,37 @@ package relation
import ( import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/pagination"
) )
const FriendRequestModelTableName = "friend_requests"
type FriendRequestModel struct { type FriendRequestModel struct {
FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` FromUserID string `bson:"from_user_id"`
ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` ToUserID string `bson:"to_user_id"`
HandleResult int32 `gorm:"column:handle_result"` HandleResult int32 `bson:"handle_result"`
ReqMsg string `gorm:"column:req_msg;size:255"` ReqMsg string `bson:"req_msg"`
CreateTime time.Time `gorm:"column:create_time; autoCreateTime"` CreateTime time.Time `bson:"create_time"`
HandlerUserID string `gorm:"column:handler_user_id;size:64"` HandlerUserID string `bson:"handler_user_id"`
HandleMsg string `gorm:"column:handle_msg;size:255"` HandleMsg string `bson:"handle_msg"`
HandleTime time.Time `gorm:"column:handle_time"` HandleTime time.Time `bson:"handle_time"`
Ex string `gorm:"column:ex;size:1024"` Ex string `bson:"ex"`
}
func (FriendRequestModel) TableName() string {
return FriendRequestModelTableName
} }
type FriendRequestModelInterface interface { type FriendRequestModelInterface interface {
// 插入多条记录 // Insert multiple records
Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error) Create(ctx context.Context, friendRequests []*FriendRequestModel) (err error)
// 删除记录 // Delete record
Delete(ctx context.Context, fromUserID, toUserID string) (err error) Delete(ctx context.Context, fromUserID, toUserID string) (err error)
// 更新零值 // Update with zero values
UpdateByMap(ctx context.Context, formUserID string, toUserID string, args map[string]interface{}) (err error) 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) 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) Find(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error) Take(ctx context.Context, fromUserID, toUserID string) (friendRequest *FriendRequestModel, err error)
// 获取toUserID收到的好友申请列表 // Get list of friend requests received by toUserID
FindToUserID( FindToUserID(ctx context.Context, toUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error)
ctx context.Context, // Get list of friend requests sent by fromUserID
toUserID string, FindFromUserID(ctx context.Context, fromUserID string, pagination pagination.Pagination) (total int64, friendRequests []*FriendRequestModel, err error)
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) FindBothFriendRequests(ctx context.Context, fromUserID, toUserID string) (friends []*FriendRequestModel, err error)
NewTx(tx any) FriendRequestModelInterface
} }

View File

@ -17,48 +17,35 @@ package relation
import ( import (
"context" "context"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupModelTableName = "groups"
) )
type GroupModel struct { type GroupModel struct {
GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"` GroupID string `bson:"group_id"`
GroupName string `gorm:"column:name;size:255" json:"groupName"` GroupName string `bson:"group_name"`
Notification string `gorm:"column:notification;size:255" json:"notification"` Notification string `bson:"notification"`
Introduction string `gorm:"column:introduction;size:255" json:"introduction"` Introduction string `bson:"introduction"`
FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` FaceURL string `bson:"face_url"`
CreateTime time.Time `gorm:"column:create_time;index:create_time;autoCreateTime"` CreateTime time.Time `bson:"create_time"`
Ex string `gorm:"column:ex" json:"ex;size:1024"` Ex string `bson:"ex"`
Status int32 `gorm:"column:status"` Status int32 `bson:"status"`
CreatorUserID string `gorm:"column:creator_user_id;size:64"` CreatorUserID string `bson:"creator_user_id"`
GroupType int32 `gorm:"column:group_type"` GroupType int32 `bson:"group_type"`
NeedVerification int32 `gorm:"column:need_verification"` NeedVerification int32 `bson:"need_verification"`
LookMemberInfo int32 `gorm:"column:look_member_info" json:"lookMemberInfo"` LookMemberInfo int32 `bson:"look_member_info"`
ApplyMemberFriend int32 `gorm:"column:apply_member_friend" json:"applyMemberFriend"` ApplyMemberFriend int32 `bson:"apply_member_friend"`
NotificationUpdateTime time.Time `gorm:"column:notification_update_time"` NotificationUpdateTime time.Time `bson:"notification_update_time"`
NotificationUserID string `gorm:"column:notification_user_id;size:64"` NotificationUserID string `bson:"notification_user_id"`
}
func (GroupModel) TableName() string {
return GroupModelTableName
} }
type GroupModelInterface interface { type GroupModelInterface interface {
NewTx(tx any) GroupModelInterface
Create(ctx context.Context, groups []*GroupModel) (err error) Create(ctx context.Context, groups []*GroupModel) (err error)
UpdateMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) UpdateMap(ctx context.Context, groupID string, args map[string]any) (err error)
UpdateStatus(ctx context.Context, groupID string, status int32) (err error) UpdateState(ctx context.Context, groupID string, state int32) (err error)
Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, 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) Take(ctx context.Context, groupID string) (group *GroupModel, err error)
Search( Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*GroupModel, err error)
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) CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
// 获取范围内群增量 // 获取范围内群增量

View File

@ -17,58 +17,41 @@ package relation
import ( import (
"context" "context"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupMemberModelTableName = "group_members"
) )
type GroupMemberModel struct { type GroupMemberModel struct {
GroupID string `gorm:"column:group_id;primary_key;size:64"` GroupID string `bson:"group_id"`
UserID string `gorm:"column:user_id;primary_key;size:64"` UserID string `bson:"user_id"`
Nickname string `gorm:"column:nickname;size:255"` Nickname string `bson:"nickname"`
FaceURL string `gorm:"column:user_group_face_url;size:255"` FaceURL string `bson:"face_url"`
RoleLevel int32 `gorm:"column:role_level"` RoleLevel int32 `bson:"role_level"`
JoinTime time.Time `gorm:"column:join_time"` JoinTime time.Time `bson:"join_time"`
JoinSource int32 `gorm:"column:join_source"` JoinSource int32 `bson:"join_source"`
InviterUserID string `gorm:"column:inviter_user_id;size:64"` InviterUserID string `bson:"inviter_user_id"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"` OperatorUserID string `bson:"operator_user_id"`
MuteEndTime time.Time `gorm:"column:mute_end_time"` MuteEndTime time.Time `bson:"mute_end_time"`
Ex string `gorm:"column:ex;size:1024"` Ex string `bson:"ex"`
}
func (GroupMemberModel) TableName() string {
return GroupMemberModelTableName
} }
type GroupMemberModelInterface interface { type GroupMemberModelInterface interface {
NewTx(tx any) GroupMemberModelInterface //NewTx(tx any) GroupMemberModelInterface
Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error) Create(ctx context.Context, groupMembers []*GroupMemberModel) (err error)
Delete(ctx context.Context, groupID string, userIDs []string) (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) 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) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) 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) FindMemberUserID(ctx context.Context, groupID string) (userIDs []string, err error)
Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error) Take(ctx context.Context, groupID string, userID string) (groupMember *GroupMemberModel, err error)
TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error) TakeOwner(ctx context.Context, groupID string) (groupMember *GroupMemberModel, err error)
SearchMember( SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*GroupMemberModel, err error)
ctx context.Context, FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error)
keyword string, //MapGroupMemberNum(ctx context.Context, groupIDs []string) (count map[string]uint32, err error)
groupIDs []string, //FindJoinUserID(ctx context.Context, groupIDs []string) (groupUsers map[string][]string, err error)
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) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error)
TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, 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) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error)
IsUpdateRoleLevel(data map[string]any) bool
} }

View File

@ -17,45 +17,30 @@ package relation
import ( import (
"context" "context"
"time" "time"
)
const ( "github.com/OpenIMSDK/tools/pagination"
GroupRequestModelTableName = "group_requests"
) )
type GroupRequestModel struct { type GroupRequestModel struct {
UserID string `gorm:"column:user_id;primary_key;size:64"` UserID string `bson:"user_id"`
GroupID string `gorm:"column:group_id;primary_key;size:64"` GroupID string `bson:"group_id"`
HandleResult int32 `gorm:"column:handle_result"` HandleResult int32 `bson:"handle_result"`
ReqMsg string `gorm:"column:req_msg;size:1024"` ReqMsg string `bson:"req_msg"`
HandledMsg string `gorm:"column:handle_msg;size:1024"` HandledMsg string `bson:"handled_msg"`
ReqTime time.Time `gorm:"column:req_time"` ReqTime time.Time `bson:"req_time"`
HandleUserID string `gorm:"column:handle_user_id;size:64"` HandleUserID string `bson:"handle_user_id"`
HandledTime time.Time `gorm:"column:handle_time"` HandledTime time.Time `bson:"handled_time"`
JoinSource int32 `gorm:"column:join_source"` JoinSource int32 `bson:"join_source"`
InviterUserID string `gorm:"column:inviter_user_id;size:64"` InviterUserID string `bson:"inviter_user_id"`
Ex string `gorm:"column:ex;size:1024"` Ex string `bson:"ex"`
}
func (GroupRequestModel) TableName() string {
return GroupRequestModelTableName
} }
type GroupRequestModelInterface interface { type GroupRequestModelInterface interface {
NewTx(tx any) GroupRequestModelInterface
Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error) Create(ctx context.Context, groupRequests []*GroupRequestModel) (err error)
Delete(ctx context.Context, groupID string, userID string) (err error) Delete(ctx context.Context, groupID string, userID string) (err error)
UpdateHandler(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32) (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) Take(ctx context.Context, groupID string, userID string) (groupRequest *GroupRequestModel, err error)
FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*GroupRequestModel, error) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*GroupRequestModel, error)
Page( Page(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error)
ctx context.Context, PageGroup(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (total int64, groups []*GroupRequestModel, err error)
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)
} }

View File

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

Some files were not shown because too many files have changed in this diff Show More