Merge branch 'main' into main
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package apistruct
|
||||
|
||||
import (
|
||||
sdkws "github.com/OpenIMSDK/protocol/sdkws"
|
||||
sdkws "github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
// SendMsg defines the structure for sending messages with various metadata.
|
||||
|
||||
@@ -29,6 +29,7 @@ type PictureElem struct {
|
||||
BigPicture PictureBaseInfo `mapstructure:"bigPicture" validate:"required"`
|
||||
SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture" validate:"required"`
|
||||
}
|
||||
|
||||
type SoundElem struct {
|
||||
UUID string `mapstructure:"uuid"`
|
||||
SoundPath string `mapstructure:"soundPath"`
|
||||
@@ -36,6 +37,7 @@ type SoundElem struct {
|
||||
DataSize int64 `mapstructure:"dataSize"`
|
||||
Duration int64 `mapstructure:"duration" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
type VideoElem struct {
|
||||
VideoPath string `mapstructure:"videoPath"`
|
||||
VideoUUID string `mapstructure:"videoUUID"`
|
||||
@@ -50,6 +52,7 @@ type VideoElem struct {
|
||||
SnapshotWidth int32 `mapstructure:"snapshotWidth" validate:"required"`
|
||||
SnapshotHeight int32 `mapstructure:"snapshotHeight" validate:"required"`
|
||||
}
|
||||
|
||||
type FileElem struct {
|
||||
FilePath string `mapstructure:"filePath"`
|
||||
UUID string `mapstructure:"uuid"`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
+13
-50
@@ -18,12 +18,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mcontext"
|
||||
"github.com/OpenIMSDK/tools/tokenverify"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
func Secret(secret string) jwt.Keyfunc {
|
||||
@@ -32,63 +30,28 @@ func Secret(secret string) jwt.Keyfunc {
|
||||
}
|
||||
}
|
||||
|
||||
func CheckAccessV3(ctx context.Context, ownerUserID string, config *config.GlobalConfig) (err error) {
|
||||
func CheckAccessV3(ctx context.Context, ownerUserID string, imAdminUserID []string) (err error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
if len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID) {
|
||||
return nil
|
||||
}
|
||||
if utils.IsContain(opUserID, config.IMAdmin.UserID) {
|
||||
if datautil.Contain(opUserID, imAdminUserID...) {
|
||||
return nil
|
||||
}
|
||||
if opUserID == ownerUserID {
|
||||
return nil
|
||||
}
|
||||
return errs.ErrNoPermission.Wrap("ownerUserID", ownerUserID)
|
||||
return servererrs.ErrNoPermission.WrapMsg("ownerUserID", ownerUserID)
|
||||
}
|
||||
|
||||
func IsAppManagerUid(ctx context.Context, config *config.GlobalConfig) bool {
|
||||
return (len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID)) ||
|
||||
utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID)
|
||||
func IsAppManagerUid(ctx context.Context, imAdminUserID []string) bool {
|
||||
return datautil.Contain(mcontext.GetOpUserID(ctx), imAdminUserID...)
|
||||
}
|
||||
|
||||
func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error {
|
||||
if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) {
|
||||
func CheckAdmin(ctx context.Context, imAdminUserID []string) error {
|
||||
if datautil.Contain(mcontext.GetOpUserID(ctx), imAdminUserID...) {
|
||||
return nil
|
||||
}
|
||||
if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
|
||||
return nil
|
||||
}
|
||||
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx)))
|
||||
return servererrs.ErrNoPermission.WrapMsg(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx)))
|
||||
}
|
||||
|
||||
func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error {
|
||||
if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
|
||||
return nil
|
||||
}
|
||||
if len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID) {
|
||||
return nil
|
||||
}
|
||||
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx)))
|
||||
}
|
||||
|
||||
func ParseRedisInterfaceToken(redisToken any, secret string) (*tokenverify.Claims, error) {
|
||||
return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret(secret))
|
||||
}
|
||||
|
||||
func IsManagerUserID(opUserID string, config *config.GlobalConfig) bool {
|
||||
return (len(config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Manager.UserID)) || utils.IsContain(opUserID, config.IMAdmin.UserID)
|
||||
}
|
||||
|
||||
func WsVerifyToken(token, userID, secret string, platformID int) error {
|
||||
claim, err := tokenverify.GetClaimFromToken(token, Secret(secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if claim.UserID != userID {
|
||||
return errs.ErrTokenInvalid.Wrap(fmt.Sprintf("token uid %s != userID %s", claim.UserID, userID))
|
||||
}
|
||||
if claim.PlatformID != platformID {
|
||||
return errs.ErrTokenInvalid.Wrap(fmt.Sprintf("token platform %d != %d", claim.PlatformID, platformID))
|
||||
}
|
||||
return nil
|
||||
func IsManagerUserID(opUserID string, imAdminUserID []string) bool {
|
||||
return datautil.Contain(opUserID, imAdminUserID...)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
package callbackstruct
|
||||
|
||||
import "github.com/OpenIMSDK/tools/errs"
|
||||
import (
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
const (
|
||||
Next = 1
|
||||
@@ -61,7 +64,7 @@ type CommonCallbackResp struct {
|
||||
}
|
||||
|
||||
func (c CommonCallbackResp) Parse() error {
|
||||
if c.ActionCode != errs.NoError || c.NextCode == Next {
|
||||
if c.ActionCode == servererrs.NoError && c.NextCode == Next {
|
||||
return errs.NewCodeError(int(c.ErrCode), c.ErrMsg).WithDetail(c.ErrDlt)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -14,47 +14,44 @@
|
||||
|
||||
package callbackstruct
|
||||
|
||||
const CallbackBeforeInviteJoinGroupCommand = "callbackBeforeInviteJoinGroupCommand"
|
||||
const CallbackAfterJoinGroupCommand = "callbackAfterJoinGroupCommand"
|
||||
const CallbackAfterSetGroupInfoCommand = "callbackAfterSetGroupInfoCommand"
|
||||
const CallbackBeforeSetGroupInfoCommand = "callbackBeforeSetGroupInfoCommand"
|
||||
|
||||
const CallbackAfterRevokeMsgCommand = "callbackBeforeAfterMsgCommand"
|
||||
const CallbackBeforeAddBlackCommand = "callbackBeforeAddBlackCommand"
|
||||
const CallbackAfterAddFriendCommand = "callbackAfterAddFriendCommand"
|
||||
const CallbackBeforeAddFriendAgreeCommand = "callbackBeforeAddFriendAgreeCommand"
|
||||
|
||||
const CallbackAfterDeleteFriendCommand = "callbackAfterDeleteFriendCommand"
|
||||
const CallbackBeforeImportFriendsCommand = "callbackBeforeImportFriendsCommand"
|
||||
const CallbackAfterImportFriendsCommand = "callbackAfterImportFriendsCommand"
|
||||
const CallbackAfterRemoveBlackCommand = "callbackAfterRemoveBlackCommand"
|
||||
|
||||
const (
|
||||
CallbackQuitGroupCommand = "callbackQuitGroupCommand"
|
||||
CallbackKillGroupCommand = "callbackKillGroupCommand"
|
||||
CallbackDisMissGroupCommand = "callbackDisMissGroupCommand"
|
||||
CallbackBeforeInviteJoinGroupCommand = "callbackBeforeInviteJoinGroupCommand"
|
||||
CallbackAfterJoinGroupCommand = "callbackAfterJoinGroupCommand"
|
||||
CallbackAfterSetGroupInfoCommand = "callbackAfterSetGroupInfoCommand"
|
||||
CallbackBeforeSetGroupInfoCommand = "callbackBeforeSetGroupInfoCommand"
|
||||
CallbackAfterRevokeMsgCommand = "callbackBeforeAfterMsgCommand"
|
||||
CallbackBeforeAddBlackCommand = "callbackBeforeAddBlackCommand"
|
||||
CallbackAfterAddFriendCommand = "callbackAfterAddFriendCommand"
|
||||
CallbackBeforeAddFriendAgreeCommand = "callbackBeforeAddFriendAgreeCommand"
|
||||
CallbackAfterDeleteFriendCommand = "callbackAfterDeleteFriendCommand"
|
||||
CallbackBeforeImportFriendsCommand = "callbackBeforeImportFriendsCommand"
|
||||
CallbackAfterImportFriendsCommand = "callbackAfterImportFriendsCommand"
|
||||
CallbackAfterRemoveBlackCommand = "callbackAfterRemoveBlackCommand"
|
||||
CallbackAfterQuitGroupCommand = "callbackAfterQuitGroupCommand"
|
||||
CallbackAfterKickGroupCommand = "callbackAfterKickGroupCommand"
|
||||
CallbackAfterDisMissGroupCommand = "callbackAfterDisMissGroupCommand"
|
||||
CallbackBeforeJoinGroupCommand = "callbackBeforeJoinGroupCommand"
|
||||
CallbackGroupMsgReadCommand = "callbackGroupMsgReadCommand"
|
||||
CallbackMsgModifyCommand = "callbackMsgModifyCommand"
|
||||
CallbackAfterGroupMsgReadCommand = "callbackAfterGroupMsgReadCommand"
|
||||
CallbackBeforeMsgModifyCommand = "callbackBeforeMsgModifyCommand"
|
||||
CallbackAfterUpdateUserInfoCommand = "callbackAfterUpdateUserInfoCommand"
|
||||
CallbackAfterUpdateUserInfoExCommand = "callbackAfterUpdateUserInfoExCommand"
|
||||
CallbackBeforeUpdateUserInfoExCommand = "callbackBeforeUpdateUserInfoExCommand"
|
||||
CallbackBeforeUserRegisterCommand = "callbackBeforeUserRegisterCommand"
|
||||
CallbackAfterUserRegisterCommand = "callbackAfterUserRegisterCommand"
|
||||
CallbackAfterTransferGroupOwner = "callbackAfterTransferGroupOwner"
|
||||
CallbackBeforeSetFriendRemark = "callbackBeforeSetFriendRemark"
|
||||
CallbackAfterSetFriendRemark = "callbackAfterSetFriendRemark"
|
||||
CallbackSingleMsgRead = "callbackSingleMsgRead"
|
||||
CallbackAfterTransferGroupOwnerCommand = "callbackAfterTransferGroupOwnerCommand"
|
||||
CallbackBeforeSetFriendRemarkCommand = "callbackBeforeSetFriendRemarkCommand"
|
||||
CallbackAfterSetFriendRemarkCommand = "callbackAfterSetFriendRemarkCommand"
|
||||
CallbackAfterSingleMsgReadCommand = "callbackAfterSingleMsgReadCommand"
|
||||
CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand"
|
||||
CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand"
|
||||
CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand"
|
||||
CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand"
|
||||
CallbackUserOnlineCommand = "callbackUserOnlineCommand"
|
||||
CallbackUserOfflineCommand = "callbackUserOfflineCommand"
|
||||
CallbackUserKickOffCommand = "callbackUserKickOffCommand"
|
||||
CallbackOfflinePushCommand = "callbackOfflinePushCommand"
|
||||
CallbackOnlinePushCommand = "callbackOnlinePushCommand"
|
||||
CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand"
|
||||
CallbackAfterUserOnlineCommand = "callbackAfterUserOnlineCommand"
|
||||
CallbackAfterUserOfflineCommand = "callbackAfterUserOfflineCommand"
|
||||
CallbackAfterUserKickOffCommand = "callbackAfterUserKickOffCommand"
|
||||
CallbackBeforeOfflinePushCommand = "callbackBeforeOfflinePushCommand"
|
||||
CallbackBeforeOnlinePushCommand = "callbackBeforeOnlinePushCommand"
|
||||
CallbackBeforeGroupOnlinePushCommand = "callbackBeforeGroupOnlinePushCommand"
|
||||
CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand"
|
||||
CallbackBeforeUpdateUserInfoCommand = "callbackBeforeUpdateUserInfoCommand"
|
||||
CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package callbackstruct
|
||||
|
||||
import (
|
||||
common "github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
|
||||
common "github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
type CallbackCommand string
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package callbackstruct
|
||||
|
||||
import (
|
||||
sdkws "github.com/OpenIMSDK/protocol/sdkws"
|
||||
sdkws "github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
type CallbackBeforeSendSingleMsgReq struct {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package callbackstruct
|
||||
|
||||
import common "github.com/OpenIMSDK/protocol/sdkws"
|
||||
import common "github.com/openimsdk/protocol/sdkws"
|
||||
|
||||
type CallbackBeforePushReq struct {
|
||||
UserStatusBatchCallbackReq
|
||||
|
||||
@@ -20,6 +20,7 @@ type CallbackAfterRevokeMsgReq struct {
|
||||
Seq int64 `json:"seq"`
|
||||
UserID string `json:"userID"`
|
||||
}
|
||||
|
||||
type CallbackAfterRevokeMsgResp struct {
|
||||
CommonCallbackResp
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
package callbackstruct
|
||||
|
||||
import (
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/OpenIMSDK/protocol/wrapperspb"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/protocol/wrapperspb"
|
||||
)
|
||||
|
||||
type CallbackBeforeUpdateUserInfoReq struct {
|
||||
@@ -26,6 +26,7 @@ type CallbackBeforeUpdateUserInfoReq struct {
|
||||
FaceURL *string `json:"faceURL"`
|
||||
Ex *string `json:"ex"`
|
||||
}
|
||||
|
||||
type CallbackBeforeUpdateUserInfoResp struct {
|
||||
CommonCallbackResp
|
||||
Nickname *string `json:"nickName"`
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright © 2024 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 cachekey // import "github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
@@ -0,0 +1,11 @@
|
||||
package cachekey
|
||||
|
||||
import "github.com/openimsdk/protocol/constant"
|
||||
|
||||
const (
|
||||
UidPidToken = "UID_PID_TOKEN_STATUS:"
|
||||
)
|
||||
|
||||
func GetTokenKey(userID string, platformID int) string {
|
||||
return UidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
|
||||
}
|
||||
+21
-24
@@ -15,43 +15,40 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/api"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type ApiCmd struct {
|
||||
*RootCmd
|
||||
initFunc func(config *config.GlobalConfig, port int, promPort int) error
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
apiConfig *api.Config
|
||||
}
|
||||
|
||||
func NewApiCmd() *ApiCmd {
|
||||
ret := &ApiCmd{RootCmd: NewRootCmd("api"), initFunc: api.Start}
|
||||
ret.SetRootCmdPt(ret)
|
||||
ret.addPreRun()
|
||||
ret.addRunE()
|
||||
var apiConfig api.Config
|
||||
ret := &ApiCmd{apiConfig: &apiConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMAPICfgFileName: &apiConfig.RpcConfig,
|
||||
ZookeeperConfigFileName: &apiConfig.ZookeeperConfig,
|
||||
ShareFileName: &apiConfig.Share,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *ApiCmd) addPreRun() {
|
||||
a.Command.PreRun = func(cmd *cobra.Command, args []string) {
|
||||
a.port = a.getPortFlag(cmd)
|
||||
a.prometheusPort = a.getPrometheusPortFlag(cmd)
|
||||
}
|
||||
func (a *ApiCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *ApiCmd) addRunE() {
|
||||
a.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return a.initFunc(a.config, a.port, a.prometheusPort)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ApiCmd) GetPortFromConfig(portType string) int {
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.Api.OpenImApiPort[0]
|
||||
} else if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.ApiPrometheusPort[0]
|
||||
}
|
||||
return 0
|
||||
func (a *ApiCmd) runE() error {
|
||||
return api.Start(a.ctx, a.Index(), a.apiConfig)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/auth"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type AuthRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
authConfig *auth.Config
|
||||
}
|
||||
|
||||
func NewAuthRpcCmd() *AuthRpcCmd {
|
||||
var authConfig auth.Config
|
||||
ret := &AuthRpcCmd{authConfig: &authConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCAuthCfgFileName: &authConfig.RpcConfig,
|
||||
RedisConfigFileName: &authConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &authConfig.ZookeeperConfig,
|
||||
ShareFileName: &authConfig.Share,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *AuthRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *AuthRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.authConfig.ZookeeperConfig, &a.authConfig.RpcConfig.Prometheus, a.authConfig.RpcConfig.RPC.ListenIP,
|
||||
a.authConfig.RpcConfig.RPC.RegisterIP, a.authConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.authConfig.Share.RpcRegisterName.Auth, &a.authConfig.Share, a.authConfig, auth.Start)
|
||||
}
|
||||
@@ -14,13 +14,83 @@
|
||||
|
||||
package cmd
|
||||
|
||||
const (
|
||||
RpcPushServer = "push"
|
||||
RpcAuthServer = "auth"
|
||||
RpcConversationServer = "conversation"
|
||||
RpcFriendServer = "friend"
|
||||
RpcGroupServer = "group"
|
||||
RpcMsgServer = "msg"
|
||||
RpcThirdServer = "third"
|
||||
RpcUserServer = "user"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
FileName string
|
||||
NotificationFileName string
|
||||
ShareFileName string
|
||||
WebhooksConfigFileName string
|
||||
LocalCacheConfigFileName string
|
||||
KafkaConfigFileName string
|
||||
RedisConfigFileName string
|
||||
ZookeeperConfigFileName string
|
||||
MongodbConfigFileName string
|
||||
MinioConfigFileName string
|
||||
LogConfigFileName string
|
||||
OpenIMAPICfgFileName string
|
||||
OpenIMCronTaskCfgFileName string
|
||||
OpenIMMsgGatewayCfgFileName string
|
||||
OpenIMMsgTransferCfgFileName string
|
||||
OpenIMPushCfgFileName string
|
||||
OpenIMRPCAuthCfgFileName string
|
||||
OpenIMRPCConversationCfgFileName string
|
||||
OpenIMRPCFriendCfgFileName string
|
||||
OpenIMRPCGroupCfgFileName string
|
||||
OpenIMRPCMsgCfgFileName string
|
||||
OpenIMRPCThirdCfgFileName string
|
||||
OpenIMRPCUserCfgFileName string
|
||||
)
|
||||
|
||||
var ConfigEnvPrefixMap map[string]string
|
||||
|
||||
func init() {
|
||||
FileName = "config.yaml"
|
||||
NotificationFileName = "notification.yml"
|
||||
ShareFileName = "share.yml"
|
||||
WebhooksConfigFileName = "webhooks.yml"
|
||||
LocalCacheConfigFileName = "local-cache.yml"
|
||||
KafkaConfigFileName = "kafka.yml"
|
||||
RedisConfigFileName = "redis.yml"
|
||||
ZookeeperConfigFileName = "zookeeper.yml"
|
||||
MongodbConfigFileName = "mongodb.yml"
|
||||
MinioConfigFileName = "minio.yml"
|
||||
LogConfigFileName = "log.yml"
|
||||
OpenIMAPICfgFileName = "openim-api.yml"
|
||||
OpenIMCronTaskCfgFileName = "openim-crontask.yml"
|
||||
OpenIMMsgGatewayCfgFileName = "openim-msggateway.yml"
|
||||
OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml"
|
||||
OpenIMPushCfgFileName = "openim-push.yml"
|
||||
OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml"
|
||||
OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml"
|
||||
OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml"
|
||||
OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml"
|
||||
OpenIMRPCMsgCfgFileName = "openim-rpc-msg.yml"
|
||||
OpenIMRPCThirdCfgFileName = "openim-rpc-third.yml"
|
||||
OpenIMRPCUserCfgFileName = "openim-rpc-user.yml"
|
||||
|
||||
ConfigEnvPrefixMap = make(map[string]string)
|
||||
fileNames := []string{
|
||||
FileName, NotificationFileName, ShareFileName, WebhooksConfigFileName,
|
||||
KafkaConfigFileName, RedisConfigFileName, ZookeeperConfigFileName,
|
||||
MongodbConfigFileName, MinioConfigFileName, LogConfigFileName,
|
||||
OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName,
|
||||
OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMRPCAuthCfgFileName,
|
||||
OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName,
|
||||
OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName,
|
||||
}
|
||||
|
||||
for _, fileName := range fileNames {
|
||||
envKey := strings.TrimSuffix(strings.TrimSuffix(fileName, ".yml"), ".yaml")
|
||||
envKey = "IMENV_" + envKey
|
||||
envKey = strings.ToUpper(strings.ReplaceAll(envKey, "-", "_"))
|
||||
ConfigEnvPrefixMap[fileName] = envKey
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
FlagConf = "config_folder_path"
|
||||
FlagTransferIndex = "index"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/conversation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type ConversationRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
conversationConfig *conversation.Config
|
||||
}
|
||||
|
||||
func NewConversationRpcCmd() *ConversationRpcCmd {
|
||||
var conversationConfig conversation.Config
|
||||
ret := &ConversationRpcCmd{conversationConfig: &conversationConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCConversationCfgFileName: &conversationConfig.RpcConfig,
|
||||
RedisConfigFileName: &conversationConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &conversationConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &conversationConfig.MongodbConfig,
|
||||
ShareFileName: &conversationConfig.Share,
|
||||
NotificationFileName: &conversationConfig.NotificationConfig,
|
||||
LocalCacheConfigFileName: &conversationConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *ConversationRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *ConversationRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.conversationConfig.ZookeeperConfig, &a.conversationConfig.RpcConfig.Prometheus, a.conversationConfig.RpcConfig.RPC.ListenIP,
|
||||
a.conversationConfig.RpcConfig.RPC.RegisterIP, a.conversationConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.conversationConfig.Share.RpcRegisterName.Conversation, &a.conversationConfig.Share, a.conversationConfig, conversation.Start)
|
||||
}
|
||||
+21
-15
@@ -15,34 +15,40 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/tools"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type CronTaskCmd struct {
|
||||
*RootCmd
|
||||
initFunc func(config *config.GlobalConfig) error
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
cronTaskConfig *tools.CronTaskConfig
|
||||
}
|
||||
|
||||
func NewCronTaskCmd() *CronTaskCmd {
|
||||
ret := &CronTaskCmd{RootCmd: NewRootCmd("cronTask", WithCronTaskLogName()),
|
||||
initFunc: tools.StartTask}
|
||||
ret.addRunE()
|
||||
ret.SetRootCmdPt(ret)
|
||||
var cronTaskConfig tools.CronTaskConfig
|
||||
ret := &CronTaskCmd{cronTaskConfig: &cronTaskConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMCronTaskCfgFileName: &cronTaskConfig.CronTask,
|
||||
ZookeeperConfigFileName: &cronTaskConfig.ZookeeperConfig,
|
||||
ShareFileName: &cronTaskConfig.Share,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *CronTaskCmd) addRunE() {
|
||||
c.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return c.initFunc(c.config)
|
||||
}
|
||||
func (a *CronTaskCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (c *CronTaskCmd) Exec() error {
|
||||
return c.Execute()
|
||||
}
|
||||
|
||||
func (c *CronTaskCmd) GetPortFromConfig(portType string) int {
|
||||
return 0
|
||||
func (a *CronTaskCmd) runE() error {
|
||||
return tools.Start(a.ctx, a.cronTaskConfig)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/friend"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type FriendRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
friendConfig *friend.Config
|
||||
}
|
||||
|
||||
func NewFriendRpcCmd() *FriendRpcCmd {
|
||||
var friendConfig friend.Config
|
||||
ret := &FriendRpcCmd{friendConfig: &friendConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCFriendCfgFileName: &friendConfig.RpcConfig,
|
||||
RedisConfigFileName: &friendConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &friendConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &friendConfig.MongodbConfig,
|
||||
ShareFileName: &friendConfig.Share,
|
||||
NotificationFileName: &friendConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &friendConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &friendConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *FriendRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *FriendRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.friendConfig.ZookeeperConfig, &a.friendConfig.RpcConfig.Prometheus, a.friendConfig.RpcConfig.RPC.ListenIP,
|
||||
a.friendConfig.RpcConfig.RPC.RegisterIP, a.friendConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.friendConfig.Share.RpcRegisterName.Friend, &a.friendConfig.Share, a.friendConfig, friend.Start)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/group"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type GroupRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
groupConfig *group.Config
|
||||
}
|
||||
|
||||
func NewGroupRpcCmd() *GroupRpcCmd {
|
||||
var groupConfig group.Config
|
||||
ret := &GroupRpcCmd{groupConfig: &groupConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCGroupCfgFileName: &groupConfig.RpcConfig,
|
||||
RedisConfigFileName: &groupConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &groupConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &groupConfig.MongodbConfig,
|
||||
ShareFileName: &groupConfig.Share,
|
||||
NotificationFileName: &groupConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &groupConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &groupConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *GroupRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *GroupRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.groupConfig.ZookeeperConfig, &a.groupConfig.RpcConfig.Prometheus, a.groupConfig.RpcConfig.RPC.ListenIP,
|
||||
a.groupConfig.RpcConfig.RPC.RegisterIP, a.groupConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.groupConfig.Share.RpcRegisterName.Group, &a.groupConfig.Share, a.groupConfig, group.Start)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/msg"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type MsgRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
msgConfig *msg.Config
|
||||
}
|
||||
|
||||
func NewMsgRpcCmd() *MsgRpcCmd {
|
||||
var msgConfig msg.Config
|
||||
ret := &MsgRpcCmd{msgConfig: &msgConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCMsgCfgFileName: &msgConfig.RpcConfig,
|
||||
RedisConfigFileName: &msgConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &msgConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &msgConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &msgConfig.KafkaConfig,
|
||||
ShareFileName: &msgConfig.Share,
|
||||
NotificationFileName: &msgConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &msgConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &msgConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *MsgRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *MsgRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.msgConfig.ZookeeperConfig, &a.msgConfig.RpcConfig.Prometheus, a.msgConfig.RpcConfig.RPC.ListenIP,
|
||||
a.msgConfig.RpcConfig.RPC.RegisterIP, a.msgConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.msgConfig.Share.RpcRegisterName.Msg, &a.msgConfig.Share, a.msgConfig, msg.Start)
|
||||
}
|
||||
@@ -15,61 +15,43 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/msggateway"
|
||||
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type MsgGatewayCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
msgGatewayConfig *msggateway.Config
|
||||
}
|
||||
|
||||
func NewMsgGatewayCmd() *MsgGatewayCmd {
|
||||
ret := &MsgGatewayCmd{NewRootCmd("msgGateway")}
|
||||
ret.addRunE()
|
||||
ret.SetRootCmdPt(ret)
|
||||
var msgGatewayConfig msggateway.Config
|
||||
ret := &MsgGatewayCmd{msgGatewayConfig: &msgGatewayConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMMsgGatewayCfgFileName: &msgGatewayConfig.MsgGateway,
|
||||
ZookeeperConfigFileName: &msgGatewayConfig.ZookeeperConfig,
|
||||
ShareFileName: &msgGatewayConfig.Share,
|
||||
WebhooksConfigFileName: &msgGatewayConfig.WebhooksConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *MsgGatewayCmd) AddWsPortFlag() {
|
||||
m.Command.Flags().IntP(constant.FlagWsPort, "w", 0, "ws server listen port")
|
||||
}
|
||||
|
||||
func (m *MsgGatewayCmd) getWsPortFlag(cmd *cobra.Command) int {
|
||||
port, err := cmd.Flags().GetInt(constant.FlagWsPort)
|
||||
if err != nil {
|
||||
log.Println("Error getting ws port flag:", err)
|
||||
}
|
||||
if port == 0 {
|
||||
port = m.PortFromConfig(constant.FlagWsPort)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func (m *MsgGatewayCmd) addRunE() {
|
||||
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return msggateway.RunWsAndServer(m.config, m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd))
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MsgGatewayCmd) Exec() error {
|
||||
return m.Execute()
|
||||
}
|
||||
|
||||
func (m *MsgGatewayCmd) GetPortFromConfig(portType string) int {
|
||||
switch portType {
|
||||
case constant.FlagWsPort:
|
||||
return m.config.LongConnSvr.OpenImWsPort[0]
|
||||
|
||||
case constant.FlagPort:
|
||||
return m.config.LongConnSvr.OpenImMessageGatewayPort[0]
|
||||
|
||||
case constant.FlagPrometheusPort:
|
||||
return m.config.Prometheus.MessageGatewayPrometheusPort[0]
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
func (m *MsgGatewayCmd) runE() error {
|
||||
return msggateway.Start(m.ctx, m.Index(), m.msgGatewayConfig)
|
||||
}
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/openimsdk/protocol/auth"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"gotest.tools/assert"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// MockRootCmd is a mock type for the RootCmd type
|
||||
@@ -32,20 +33,29 @@ func (m *MockRootCmd) Execute() error {
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func TestMsgGatewayCmd_GetPortFromConfig(t *testing.T) {
|
||||
msgGatewayCmd := &MsgGatewayCmd{RootCmd: &RootCmd{}}
|
||||
tests := []struct {
|
||||
portType string
|
||||
want int
|
||||
}{
|
||||
{constant.FlagWsPort, 8080}, // Replace 8080 with the expected port from the config
|
||||
{constant.FlagPort, 8081}, // Replace 8081 with the expected port from the config
|
||||
{"invalid", 0},
|
||||
func TestName(t *testing.T) {
|
||||
resp := &apiresp.ApiResponse{
|
||||
ErrCode: 1234,
|
||||
ErrMsg: "test",
|
||||
ErrDlt: "4567",
|
||||
Data: &auth.UserTokenResp{
|
||||
Token: "1234567",
|
||||
ExpireTimeSeconds: math.MaxInt64,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.portType, func(t *testing.T) {
|
||||
got := msgGatewayCmd.GetPortFromConfig(tt.portType)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
data, err := resp.MarshalJSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(string(data))
|
||||
|
||||
var rReso apiresp.ApiResponse
|
||||
rReso.Data = &auth.UserTokenResp{}
|
||||
|
||||
if err := jsonutil.JsonUnmarshal(data, &rReso); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
t.Logf("%+v\n", rReso)
|
||||
|
||||
}
|
||||
|
||||
@@ -15,53 +15,44 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/msgtransfer"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type MsgTransferCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
msgTransferConfig *msgtransfer.Config
|
||||
}
|
||||
|
||||
func NewMsgTransferCmd() *MsgTransferCmd {
|
||||
ret := &MsgTransferCmd{NewRootCmd("msgTransfer")}
|
||||
ret.addRunE()
|
||||
ret.SetRootCmdPt(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *MsgTransferCmd) addRunE() {
|
||||
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return msgtransfer.StartTransfer(m.config, m.getPrometheusPortFlag(cmd))
|
||||
var msgTransferConfig msgtransfer.Config
|
||||
ret := &MsgTransferCmd{msgTransferConfig: &msgTransferConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMMsgTransferCfgFileName: &msgTransferConfig.MsgTransfer,
|
||||
RedisConfigFileName: &msgTransferConfig.RedisConfig,
|
||||
MongodbConfigFileName: &msgTransferConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &msgTransferConfig.KafkaConfig,
|
||||
ZookeeperConfigFileName: &msgTransferConfig.ZookeeperConfig,
|
||||
ShareFileName: &msgTransferConfig.Share,
|
||||
WebhooksConfigFileName: &msgTransferConfig.WebhooksConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *MsgTransferCmd) Exec() error {
|
||||
return m.Execute()
|
||||
}
|
||||
|
||||
func (m *MsgTransferCmd) GetPortFromConfig(portType string) int {
|
||||
if portType == constant.FlagPort {
|
||||
return 0
|
||||
} else if portType == constant.FlagPrometheusPort {
|
||||
n := m.getTransferProgressFlagValue()
|
||||
return m.config.Prometheus.MessageTransferPrometheusPort[n]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MsgTransferCmd) AddTransferProgressFlag() {
|
||||
m.Command.Flags().IntP(constant.FlagTransferProgressIndex, "n", 0, "transfer progress index")
|
||||
}
|
||||
|
||||
func (m *MsgTransferCmd) getTransferProgressFlagValue() int {
|
||||
nIndex, err := m.Command.Flags().GetInt(constant.FlagTransferProgressIndex)
|
||||
if err != nil {
|
||||
fmt.Println("get transfer cmd error,make sure it is k8s env or not")
|
||||
return 0
|
||||
}
|
||||
return nIndex
|
||||
func (m *MsgTransferCmd) runE() error {
|
||||
return msgtransfer.Start(m.ctx, m.Index(), m.msgTransferConfig)
|
||||
}
|
||||
|
||||
+10
-25
@@ -15,19 +15,24 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/open-im-server/v3/internal/tools"
|
||||
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type MsgUtilsCmd struct {
|
||||
cobra.Command
|
||||
MsgTool *tools.MsgTool
|
||||
}
|
||||
|
||||
func (m *MsgUtilsCmd) AddUserIDFlag() {
|
||||
m.Command.PersistentFlags().StringP("userID", "u", "", "openIM userID")
|
||||
}
|
||||
func (m *MsgUtilsCmd) AddIndexFlag() {
|
||||
m.Command.PersistentFlags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
}
|
||||
|
||||
func (m *MsgUtilsCmd) AddConfigDirFlag() {
|
||||
m.Command.PersistentFlags().StringP(FlagConf, "c", "", "path of config directory")
|
||||
|
||||
}
|
||||
|
||||
func (m *MsgUtilsCmd) getUserIDFlag(cmdLines *cobra.Command) string {
|
||||
userID, _ := cmdLines.Flags().GetString("userID")
|
||||
@@ -44,7 +49,7 @@ func (m *MsgUtilsCmd) AddFixAllFlag() {
|
||||
} */
|
||||
|
||||
func (m *MsgUtilsCmd) AddClearAllFlag() {
|
||||
m.Command.PersistentFlags().BoolP("clearAll", "c", false, "openIM clear all seqs")
|
||||
m.Command.PersistentFlags().BoolP("clearAll", "", false, "openIM clear all seqs")
|
||||
}
|
||||
|
||||
/* func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool {
|
||||
@@ -136,27 +141,7 @@ func NewSeqCmd() *SeqCmd {
|
||||
|
||||
func (s *SeqCmd) GetSeqCmd() *cobra.Command {
|
||||
s.Command.Run = func(cmdLines *cobra.Command, args []string) {
|
||||
_, err := tools.InitMsgTool(s.MsgTool.Config)
|
||||
if err != nil {
|
||||
util.ExitWithError(err)
|
||||
}
|
||||
userID := s.getUserIDFlag(cmdLines)
|
||||
superGroupID := s.getSuperGroupIDFlag(cmdLines)
|
||||
// beginSeq := s.getBeginSeqFlag(cmdLines)
|
||||
// limit := s.getLimitFlag(cmdLines)
|
||||
if userID != "" {
|
||||
// seq, err := msgTool.s(context.Background(), userID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// println(seq)
|
||||
} else if superGroupID != "" {
|
||||
// seq, err := msgTool.GetSuperGroupSeq(context.Background(), superGroupID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// println(seq)
|
||||
}
|
||||
|
||||
}
|
||||
return &s.Command
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/push"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type PushRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
pushConfig *push.Config
|
||||
}
|
||||
|
||||
func NewPushRpcCmd() *PushRpcCmd {
|
||||
var pushConfig push.Config
|
||||
ret := &PushRpcCmd{pushConfig: &pushConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMPushCfgFileName: &pushConfig.RpcConfig,
|
||||
RedisConfigFileName: &pushConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &pushConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &pushConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &pushConfig.KafkaConfig,
|
||||
ShareFileName: &pushConfig.Share,
|
||||
NotificationFileName: &pushConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &pushConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &pushConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *PushRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *PushRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.pushConfig.ZookeeperConfig, &a.pushConfig.RpcConfig.Prometheus, a.pushConfig.RpcConfig.RPC.ListenIP,
|
||||
a.pushConfig.RpcConfig.RPC.RegisterIP, a.pushConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.pushConfig.Share.RpcRegisterName.Push, &a.pushConfig.Share, a.pushConfig, push.Start)
|
||||
}
|
||||
+75
-100
@@ -16,34 +16,34 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type RootCmdPt interface {
|
||||
GetPortFromConfig(portType string) int
|
||||
}
|
||||
|
||||
type RootCmd struct {
|
||||
Command cobra.Command
|
||||
Name string
|
||||
processName string
|
||||
port int
|
||||
prometheusPort int
|
||||
cmdItf RootCmdPt
|
||||
config *config.GlobalConfig
|
||||
log config.Log
|
||||
index int
|
||||
}
|
||||
|
||||
func (rc *RootCmd) Port() int {
|
||||
return rc.port
|
||||
func (r *RootCmd) Index() int {
|
||||
return r.index
|
||||
}
|
||||
|
||||
func (r *RootCmd) Port() int {
|
||||
return r.port
|
||||
}
|
||||
|
||||
type CmdOpts struct {
|
||||
loggerPrefixName string
|
||||
configMap map[string]any
|
||||
}
|
||||
|
||||
func WithCronTaskLogName() func(*CmdOpts) {
|
||||
@@ -57,41 +57,63 @@ func WithLogName(logName string) func(*CmdOpts) {
|
||||
opts.loggerPrefixName = logName
|
||||
}
|
||||
}
|
||||
func WithConfigMap(configMap map[string]any) func(*CmdOpts) {
|
||||
return func(opts *CmdOpts) {
|
||||
opts.configMap = configMap
|
||||
}
|
||||
}
|
||||
|
||||
func NewRootCmd(name string, opts ...func(*CmdOpts)) *RootCmd {
|
||||
rootCmd := &RootCmd{Name: name, config: config.NewGlobalConfig()}
|
||||
func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd {
|
||||
rootCmd := &RootCmd{processName: processName}
|
||||
cmd := cobra.Command{
|
||||
Use: "Start openIM application",
|
||||
Short: fmt.Sprintf(`Start %s `, name),
|
||||
Long: fmt.Sprintf(`Start %s `, name),
|
||||
Use: "Start openIM application",
|
||||
Long: fmt.Sprintf(`Start %s `, processName),
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return rootCmd.persistentPreRun(cmd, opts...)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: false,
|
||||
}
|
||||
cmd.Flags().StringP(FlagConf, "c", "", "path of config directory")
|
||||
cmd.Flags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number")
|
||||
|
||||
rootCmd.Command = cmd
|
||||
rootCmd.addConfFlag()
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func (rc *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error {
|
||||
if err := rc.initializeConfiguration(cmd); err != nil {
|
||||
return fmt.Errorf("failed to get configuration from command: %w", err)
|
||||
func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error {
|
||||
cmdOpts := r.applyOptions(opts...)
|
||||
if err := r.initializeConfiguration(cmd, cmdOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmdOpts := rc.applyOptions(opts...)
|
||||
|
||||
if err := rc.initializeLogger(cmdOpts); err != nil {
|
||||
return errs.Wrap(err, "failed to initialize logger")
|
||||
if err := r.initializeLogger(cmdOpts); err != nil {
|
||||
return errs.WrapMsg(err, "failed to initialize logger")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *RootCmd) initializeConfiguration(cmd *cobra.Command) error {
|
||||
return rc.getConfFromCmdAndInit(cmd)
|
||||
func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) error {
|
||||
configDirectory, _, err := r.getFlag(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Load common configuration file
|
||||
//opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share}
|
||||
for configFileName, configStruct := range opts.configMap {
|
||||
err := config.LoadConfig(filepath.Join(configDirectory, configFileName),
|
||||
ConfigEnvPrefixMap[configFileName], configStruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Load common log configuration file
|
||||
return config.LoadConfig(filepath.Join(configDirectory, LogConfigFileName),
|
||||
ConfigEnvPrefixMap[LogConfigFileName], &r.log)
|
||||
}
|
||||
|
||||
func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
|
||||
func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
|
||||
cmdOpts := defaultCmdOpts()
|
||||
for _, opt := range opts {
|
||||
opt(cmdOpts)
|
||||
@@ -100,92 +122,45 @@ func (rc *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
|
||||
return cmdOpts
|
||||
}
|
||||
|
||||
func (rc *RootCmd) initializeLogger(cmdOpts *CmdOpts) error {
|
||||
logConfig := rc.config.Log
|
||||
|
||||
return log.InitFromConfig(
|
||||
func (r *RootCmd) initializeLogger(cmdOpts *CmdOpts) error {
|
||||
err := log.InitFromConfig(
|
||||
|
||||
cmdOpts.loggerPrefixName,
|
||||
rc.Name,
|
||||
logConfig.RemainLogLevel,
|
||||
logConfig.IsStdout,
|
||||
logConfig.IsJson,
|
||||
logConfig.StorageLocation,
|
||||
logConfig.RemainRotationCount,
|
||||
logConfig.RotationTime,
|
||||
r.processName,
|
||||
r.log.RemainLogLevel,
|
||||
r.log.IsStdout,
|
||||
r.log.IsJson,
|
||||
r.log.StorageLocation,
|
||||
r.log.RemainRotationCount,
|
||||
r.log.RotationTime,
|
||||
config.Version,
|
||||
)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
return errs.Wrap(log.InitConsoleLogger(r.processName, r.log.RemainLogLevel, r.log.IsJson, config.Version))
|
||||
|
||||
}
|
||||
|
||||
func defaultCmdOpts() *CmdOpts {
|
||||
return &CmdOpts{
|
||||
loggerPrefixName: "openim-all",
|
||||
loggerPrefixName: "openim-service-log",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RootCmd) SetRootCmdPt(cmdItf RootCmdPt) {
|
||||
r.cmdItf = cmdItf
|
||||
}
|
||||
|
||||
func (r *RootCmd) addConfFlag() {
|
||||
r.Command.Flags().StringP(constant.FlagConf, "c", "", "path to config file folder")
|
||||
}
|
||||
|
||||
func (r *RootCmd) AddPortFlag() {
|
||||
r.Command.Flags().IntP(constant.FlagPort, "p", 0, "server listen port")
|
||||
}
|
||||
|
||||
func (r *RootCmd) getPortFlag(cmd *cobra.Command) int {
|
||||
port, err := cmd.Flags().GetInt(constant.FlagPort)
|
||||
func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) {
|
||||
configDirectory, err := cmd.Flags().GetString(FlagConf)
|
||||
if err != nil {
|
||||
// Wrapping the error with additional context
|
||||
return 0
|
||||
return "", 0, errs.Wrap(err)
|
||||
}
|
||||
if port == 0 {
|
||||
port = r.PortFromConfig(constant.FlagPort)
|
||||
index, err := cmd.Flags().GetInt(FlagTransferIndex)
|
||||
if err != nil {
|
||||
return "", 0, errs.Wrap(err)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
// // GetPortFlag returns the port flag.
|
||||
func (r *RootCmd) GetPortFlag() int {
|
||||
return r.port
|
||||
}
|
||||
|
||||
func (r *RootCmd) AddPrometheusPortFlag() {
|
||||
r.Command.Flags().IntP(constant.FlagPrometheusPort, "", 0, "server prometheus listen port")
|
||||
}
|
||||
|
||||
func (r *RootCmd) getPrometheusPortFlag(cmd *cobra.Command) int {
|
||||
port, err := cmd.Flags().GetInt(constant.FlagPrometheusPort)
|
||||
if err != nil || port == 0 {
|
||||
port = r.PortFromConfig(constant.FlagPrometheusPort)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func (r *RootCmd) GetPrometheusPortFlag() int {
|
||||
return r.prometheusPort
|
||||
}
|
||||
|
||||
func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error {
|
||||
configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf)
|
||||
fmt.Println("The directory of the configuration file to start the process:", configFolderPath)
|
||||
return config2.InitConfig(r.config, configFolderPath)
|
||||
r.index = index
|
||||
return configDirectory, index, nil
|
||||
}
|
||||
|
||||
func (r *RootCmd) Execute() error {
|
||||
return r.Command.Execute()
|
||||
}
|
||||
|
||||
func (r *RootCmd) AddCommand(cmds ...*cobra.Command) {
|
||||
r.Command.AddCommand(cmds...)
|
||||
}
|
||||
|
||||
func (r *RootCmd) PortFromConfig(portType string) int {
|
||||
// Retrieve the port and cache it
|
||||
port := r.cmdItf.GetPortFromConfig(portType)
|
||||
return port
|
||||
}
|
||||
|
||||
@@ -1,156 +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 cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type rpcInitFuc func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error
|
||||
|
||||
type RpcCmd struct {
|
||||
*RootCmd
|
||||
RpcRegisterName string
|
||||
initFunc rpcInitFuc
|
||||
}
|
||||
|
||||
func NewRpcCmd(name string, initFunc rpcInitFuc) *RpcCmd {
|
||||
ret := &RpcCmd{RootCmd: NewRootCmd(name), initFunc: initFunc}
|
||||
ret.addPreRun()
|
||||
ret.addRunE()
|
||||
ret.SetRootCmdPt(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *RpcCmd) addPreRun() {
|
||||
a.Command.PreRun = func(cmd *cobra.Command, args []string) {
|
||||
a.port = a.getPortFlag(cmd)
|
||||
a.prometheusPort = a.getPrometheusPortFlag(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *RpcCmd) addRunE() {
|
||||
a.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
rpcRegisterName, err := a.GetRpcRegisterNameFromConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
return a.StartSvr(rpcRegisterName, a.initFunc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *RpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *RpcCmd) StartSvr(name string, rpcFn func(config *config2.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error {
|
||||
if a.GetPortFlag() == 0 {
|
||||
return errs.Wrap(errors.New("port is required"))
|
||||
}
|
||||
return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), a.config, rpcFn)
|
||||
}
|
||||
|
||||
func (a *RpcCmd) GetPortFromConfig(portType string) int {
|
||||
switch a.Name {
|
||||
case RpcPushServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImPushPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.PushPrometheusPort[0]
|
||||
}
|
||||
case RpcAuthServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImAuthPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.AuthPrometheusPort[0]
|
||||
}
|
||||
case RpcConversationServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImConversationPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.ConversationPrometheusPort[0]
|
||||
}
|
||||
case RpcFriendServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImFriendPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.FriendPrometheusPort[0]
|
||||
}
|
||||
case RpcGroupServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImGroupPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.GroupPrometheusPort[0]
|
||||
}
|
||||
case RpcMsgServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImMessagePort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.MessagePrometheusPort[0]
|
||||
}
|
||||
case RpcThirdServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImThirdPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.ThirdPrometheusPort[0]
|
||||
}
|
||||
case RpcUserServer:
|
||||
if portType == constant.FlagPort {
|
||||
return a.config.RpcPort.OpenImUserPort[0]
|
||||
}
|
||||
if portType == constant.FlagPrometheusPort {
|
||||
return a.config.Prometheus.UserPrometheusPort[0]
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a *RpcCmd) GetRpcRegisterNameFromConfig() (string, error) {
|
||||
switch a.Name {
|
||||
case RpcPushServer:
|
||||
return a.config.RpcRegisterName.OpenImPushName, nil
|
||||
case RpcAuthServer:
|
||||
return a.config.RpcRegisterName.OpenImAuthName, nil
|
||||
case RpcConversationServer:
|
||||
return a.config.RpcRegisterName.OpenImConversationName, nil
|
||||
case RpcFriendServer:
|
||||
return a.config.RpcRegisterName.OpenImFriendName, nil
|
||||
case RpcGroupServer:
|
||||
return a.config.RpcRegisterName.OpenImGroupName, nil
|
||||
case RpcMsgServer:
|
||||
return a.config.RpcRegisterName.OpenImMsgName, nil
|
||||
case RpcThirdServer:
|
||||
return a.config.RpcRegisterName.OpenImThirdName, nil
|
||||
case RpcUserServer:
|
||||
return a.config.RpcRegisterName.OpenImUserName, nil
|
||||
}
|
||||
return "", errs.Wrap(errors.New("can not get rpc register name"), a.Name)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/third"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type ThirdRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
thirdConfig *third.Config
|
||||
}
|
||||
|
||||
func NewThirdRpcCmd() *ThirdRpcCmd {
|
||||
var thirdConfig third.Config
|
||||
ret := &ThirdRpcCmd{thirdConfig: &thirdConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCThirdCfgFileName: &thirdConfig.RpcConfig,
|
||||
RedisConfigFileName: &thirdConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &thirdConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &thirdConfig.MongodbConfig,
|
||||
ShareFileName: &thirdConfig.Share,
|
||||
NotificationFileName: &thirdConfig.NotificationConfig,
|
||||
MinioConfigFileName: &thirdConfig.MinioConfig,
|
||||
LocalCacheConfigFileName: &thirdConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *ThirdRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *ThirdRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.thirdConfig.ZookeeperConfig, &a.thirdConfig.RpcConfig.Prometheus, a.thirdConfig.RpcConfig.RPC.ListenIP,
|
||||
a.thirdConfig.RpcConfig.RPC.RegisterIP, a.thirdConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.thirdConfig.Share.RpcRegisterName.Third, &a.thirdConfig.Share, a.thirdConfig, third.Start)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/user"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/tools/system/program"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type UserRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
userConfig *user.Config
|
||||
}
|
||||
|
||||
func NewUserRpcCmd() *UserRpcCmd {
|
||||
var userConfig user.Config
|
||||
ret := &UserRpcCmd{userConfig: &userConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCUserCfgFileName: &userConfig.RpcConfig,
|
||||
RedisConfigFileName: &userConfig.RedisConfig,
|
||||
ZookeeperConfigFileName: &userConfig.ZookeeperConfig,
|
||||
MongodbConfigFileName: &userConfig.MongodbConfig,
|
||||
KafkaConfigFileName: &userConfig.KafkaConfig,
|
||||
ShareFileName: &userConfig.Share,
|
||||
NotificationFileName: &userConfig.NotificationConfig,
|
||||
WebhooksConfigFileName: &userConfig.WebhooksConfig,
|
||||
LocalCacheConfigFileName: &userConfig.LocalCacheConfig,
|
||||
}
|
||||
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
|
||||
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
|
||||
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return ret.runE()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a *UserRpcCmd) Exec() error {
|
||||
return a.Execute()
|
||||
}
|
||||
|
||||
func (a *UserRpcCmd) runE() error {
|
||||
return startrpc.Start(a.ctx, &a.userConfig.ZookeeperConfig, &a.userConfig.RpcConfig.Prometheus, a.userConfig.RpcConfig.RPC.ListenIP,
|
||||
a.userConfig.RpcConfig.RPC.RegisterIP, a.userConfig.RpcConfig.RPC.Ports,
|
||||
a.Index(), a.userConfig.Share.RpcRegisterName.User, &a.userConfig.Share, a.userConfig, user.Start)
|
||||
}
|
||||
+495
-414
@@ -15,433 +15,514 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/redisutil"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/s3/cos"
|
||||
"github.com/openimsdk/tools/s3/minio"
|
||||
"github.com/openimsdk/tools/s3/oss"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var Config GlobalConfig
|
||||
|
||||
const ConfKey = "conf"
|
||||
|
||||
type CallBackConfig struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
CallbackTimeOut int `yaml:"timeout"`
|
||||
CallbackFailedContinue *bool `yaml:"failedContinue"`
|
||||
}
|
||||
|
||||
type NotificationConf struct {
|
||||
IsSendMsg bool `yaml:"isSendMsg"`
|
||||
ReliabilityLevel int `yaml:"reliabilityLevel"` // 1 online 2 persistent
|
||||
UnreadCount bool `yaml:"unreadCount"`
|
||||
OfflinePush POfflinePush `yaml:"offlinePush"`
|
||||
}
|
||||
|
||||
type POfflinePush struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
Title string `yaml:"title"`
|
||||
Desc string `yaml:"desc"`
|
||||
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 GlobalConfig struct {
|
||||
Envs struct {
|
||||
Discovery string `yaml:"discovery"`
|
||||
}
|
||||
Zookeeper struct {
|
||||
Schema string `yaml:"schema"`
|
||||
ZkAddr []string `yaml:"address"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
} `yaml:"zookeeper"`
|
||||
|
||||
Mysql *MYSQL `yaml:"mysql"`
|
||||
|
||||
Mongo struct {
|
||||
Uri string `yaml:"uri"`
|
||||
Address []string `yaml:"address"`
|
||||
Database string `yaml:"database"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
MaxPoolSize int `yaml:"maxPoolSize"`
|
||||
} `yaml:"mongo"`
|
||||
|
||||
Redis struct {
|
||||
ClusterMode bool `yaml:"clusterMode"`
|
||||
Address []string `yaml:"address"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
EnablePipeline bool `yaml:"enablePipeline"`
|
||||
} `yaml:"redis"`
|
||||
|
||||
Kafka struct {
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
ProducerAck string `yaml:"producerAck"`
|
||||
CompressType string `yaml:"compressType"`
|
||||
Addr []string `yaml:"addr"`
|
||||
TLS *struct {
|
||||
CACrt string `yaml:"caCrt"`
|
||||
ClientCrt string `yaml:"clientCrt"`
|
||||
ClientKey string `yaml:"clientKey"`
|
||||
ClientKeyPwd string `yaml:"clientKeyPwd"`
|
||||
InsecureSkipVerify bool `yaml:"insecureSkipVerify"`
|
||||
} `yaml:"tls"`
|
||||
LatestMsgToRedis struct {
|
||||
Topic string `yaml:"topic"`
|
||||
} `yaml:"latestMsgToRedis"`
|
||||
MsgToMongo struct {
|
||||
Topic string `yaml:"topic"`
|
||||
} `yaml:"offlineMsgToMongo"`
|
||||
MsgToPush struct {
|
||||
Topic string `yaml:"topic"`
|
||||
} `yaml:"msgToPush"`
|
||||
ConsumerGroupID struct {
|
||||
MsgToRedis string `yaml:"msgToRedis"`
|
||||
MsgToMongo string `yaml:"msgToMongo"`
|
||||
MsgToMySql string `yaml:"msgToMySql"`
|
||||
MsgToPush string `yaml:"msgToPush"`
|
||||
} `yaml:"consumerGroupID"`
|
||||
} `yaml:"kafka"`
|
||||
|
||||
Rpc struct {
|
||||
RegisterIP string `yaml:"registerIP"`
|
||||
ListenIP string `yaml:"listenIP"`
|
||||
} `yaml:"rpc"`
|
||||
|
||||
Api struct {
|
||||
OpenImApiPort []int `yaml:"openImApiPort"`
|
||||
ListenIP string `yaml:"listenIP"`
|
||||
} `yaml:"api"`
|
||||
|
||||
Object struct {
|
||||
Enable string `yaml:"enable"`
|
||||
ApiURL string `yaml:"apiURL"`
|
||||
Minio struct {
|
||||
Bucket string `yaml:"bucket"`
|
||||
Endpoint string `yaml:"endpoint"`
|
||||
AccessKeyID string `yaml:"accessKeyID"`
|
||||
SecretAccessKey string `yaml:"secretAccessKey"`
|
||||
SessionToken string `yaml:"sessionToken"`
|
||||
SignEndpoint string `yaml:"signEndpoint"`
|
||||
PublicRead bool `yaml:"publicRead"`
|
||||
} `yaml:"minio"`
|
||||
Cos struct {
|
||||
BucketURL string `yaml:"bucketURL"`
|
||||
SecretID string `yaml:"secretID"`
|
||||
SecretKey string `yaml:"secretKey"`
|
||||
SessionToken string `yaml:"sessionToken"`
|
||||
PublicRead bool `yaml:"publicRead"`
|
||||
} `yaml:"cos"`
|
||||
Oss struct {
|
||||
Endpoint string `yaml:"endpoint"`
|
||||
Bucket string `yaml:"bucket"`
|
||||
BucketURL string `yaml:"bucketURL"`
|
||||
AccessKeyID string `yaml:"accessKeyID"`
|
||||
AccessKeySecret string `yaml:"accessKeySecret"`
|
||||
SessionToken string `yaml:"sessionToken"`
|
||||
PublicRead bool `yaml:"publicRead"`
|
||||
} `yaml:"oss"`
|
||||
Kodo struct {
|
||||
Endpoint string `yaml:"endpoint"`
|
||||
Bucket string `yaml:"bucket"`
|
||||
BucketURL string `yaml:"bucketURL"`
|
||||
AccessKeyID string `yaml:"accessKeyID"`
|
||||
AccessKeySecret string `yaml:"accessKeySecret"`
|
||||
SessionToken string `yaml:"sessionToken"`
|
||||
PublicRead bool `yaml:"publicRead"`
|
||||
} `yaml:"kodo"`
|
||||
Aws struct {
|
||||
Endpoint string `yaml:"endpoint"`
|
||||
Region string `yaml:"region"`
|
||||
Bucket string `yaml:"bucket"`
|
||||
AccessKeyID string `yaml:"accessKeyID"`
|
||||
AccessKeySecret string `yaml:"accessKeySecret"`
|
||||
PublicRead bool `yaml:"publicRead"`
|
||||
} `yaml:"aws"`
|
||||
} `yaml:"object"`
|
||||
|
||||
RpcPort struct {
|
||||
OpenImUserPort []int `yaml:"openImUserPort"`
|
||||
OpenImFriendPort []int `yaml:"openImFriendPort"`
|
||||
OpenImMessagePort []int `yaml:"openImMessagePort"`
|
||||
OpenImMessageGatewayPort []int `yaml:"openImMessageGatewayPort"`
|
||||
OpenImGroupPort []int `yaml:"openImGroupPort"`
|
||||
OpenImAuthPort []int `yaml:"openImAuthPort"`
|
||||
OpenImPushPort []int `yaml:"openImPushPort"`
|
||||
OpenImConversationPort []int `yaml:"openImConversationPort"`
|
||||
OpenImRtcPort []int `yaml:"openImRtcPort"`
|
||||
OpenImThirdPort []int `yaml:"openImThirdPort"`
|
||||
} `yaml:"rpcPort"`
|
||||
|
||||
RpcRegisterName struct {
|
||||
OpenImUserName string `yaml:"openImUserName"`
|
||||
OpenImFriendName string `yaml:"openImFriendName"`
|
||||
OpenImMsgName string `yaml:"openImMsgName"`
|
||||
OpenImPushName string `yaml:"openImPushName"`
|
||||
OpenImMessageGatewayName string `yaml:"openImMessageGatewayName"`
|
||||
OpenImGroupName string `yaml:"openImGroupName"`
|
||||
OpenImAuthName string `yaml:"openImAuthName"`
|
||||
OpenImConversationName string `yaml:"openImConversationName"`
|
||||
OpenImThirdName string `yaml:"openImThirdName"`
|
||||
} `yaml:"rpcRegisterName"`
|
||||
|
||||
Log struct {
|
||||
StorageLocation string `yaml:"storageLocation"`
|
||||
RotationTime uint `yaml:"rotationTime"`
|
||||
RemainRotationCount uint `yaml:"remainRotationCount"`
|
||||
RemainLogLevel int `yaml:"remainLogLevel"`
|
||||
IsStdout bool `yaml:"isStdout"`
|
||||
IsJson bool `yaml:"isJson"`
|
||||
WithStack bool `yaml:"withStack"`
|
||||
} `yaml:"log"`
|
||||
|
||||
LongConnSvr struct {
|
||||
OpenImMessageGatewayPort []int `yaml:"openImMessageGatewayPort"`
|
||||
OpenImWsPort []int `yaml:"openImWsPort"`
|
||||
WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"`
|
||||
WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"`
|
||||
WebsocketTimeout int `yaml:"websocketTimeout"`
|
||||
WebsocketWriteBufferSize int `yaml:"websocketWriteBufferSize"`
|
||||
} `yaml:"longConnSvr"`
|
||||
|
||||
Push struct {
|
||||
MaxConcurrentWorkers int `yaml:"maxConcurrentWorkers"`
|
||||
Enable string `yaml:"enable"`
|
||||
GeTui struct {
|
||||
PushUrl string `yaml:"pushUrl"`
|
||||
AppKey string `yaml:"appKey"`
|
||||
Intent string `yaml:"intent"`
|
||||
MasterSecret string `yaml:"masterSecret"`
|
||||
ChannelID string `yaml:"channelID"`
|
||||
ChannelName string `yaml:"channelName"`
|
||||
} `yaml:"geTui"`
|
||||
Fcm struct {
|
||||
ServiceAccount string `yaml:"serviceAccount"`
|
||||
} `yaml:"fcm"`
|
||||
Jpns struct {
|
||||
AppKey string `yaml:"appKey"`
|
||||
MasterSecret string `yaml:"masterSecret"`
|
||||
PushUrl string `yaml:"pushUrl"`
|
||||
PushIntent string `yaml:"pushIntent"`
|
||||
} `yaml:"jpns"`
|
||||
}
|
||||
Manager struct {
|
||||
UserID []string `yaml:"userID"`
|
||||
Nickname []string `yaml:"nickname"`
|
||||
} `yaml:"manager"`
|
||||
|
||||
IMAdmin struct {
|
||||
UserID []string `yaml:"userID"`
|
||||
Nickname []string `yaml:"nickname"`
|
||||
} `yaml:"im-admin"`
|
||||
|
||||
MultiLoginPolicy int `yaml:"multiLoginPolicy"`
|
||||
ChatPersistenceMysql bool `yaml:"chatPersistenceMysql"`
|
||||
MsgCacheTimeout int `yaml:"msgCacheTimeout"`
|
||||
GroupMessageHasReadReceiptEnable bool `yaml:"groupMessageHasReadReceiptEnable"`
|
||||
SingleMessageHasReadReceiptEnable bool `yaml:"singleMessageHasReadReceiptEnable"`
|
||||
RetainChatRecords int `yaml:"retainChatRecords"`
|
||||
ChatRecordsClearTime string `yaml:"chatRecordsClearTime"`
|
||||
MsgDestructTime string `yaml:"msgDestructTime"`
|
||||
Secret string `yaml:"secret"`
|
||||
EnableCronLocker bool `yaml:"enableCronLocker"`
|
||||
TokenPolicy struct {
|
||||
Expire int64 `yaml:"expire"`
|
||||
} `yaml:"tokenPolicy"`
|
||||
MessageVerify struct {
|
||||
FriendVerify *bool `yaml:"friendVerify"`
|
||||
} `yaml:"messageVerify"`
|
||||
|
||||
LocalCache localCache `yaml:"localCache"`
|
||||
|
||||
IOSPush struct {
|
||||
PushSound string `yaml:"pushSound"`
|
||||
BadgeCount bool `yaml:"badgeCount"`
|
||||
Production bool `yaml:"production"`
|
||||
} `yaml:"iosPush"`
|
||||
Callback struct {
|
||||
CallbackUrl string `yaml:"url"`
|
||||
CallbackBeforeSendSingleMsg CallBackConfig `yaml:"beforeSendSingleMsg"`
|
||||
CallbackAfterSendSingleMsg CallBackConfig `yaml:"afterSendSingleMsg"`
|
||||
CallbackBeforeSendGroupMsg CallBackConfig `yaml:"beforeSendGroupMsg"`
|
||||
CallbackAfterSendGroupMsg CallBackConfig `yaml:"afterSendGroupMsg"`
|
||||
CallbackMsgModify CallBackConfig `yaml:"msgModify"`
|
||||
CallbackSingleMsgRead CallBackConfig `yaml:"singleMsgRead"`
|
||||
CallbackGroupMsgRead CallBackConfig `yaml:"groupMsgRead"`
|
||||
CallbackUserOnline CallBackConfig `yaml:"userOnline"`
|
||||
CallbackUserOffline CallBackConfig `yaml:"userOffline"`
|
||||
CallbackUserKickOff CallBackConfig `yaml:"userKickOff"`
|
||||
CallbackOfflinePush CallBackConfig `yaml:"offlinePush"`
|
||||
CallbackOnlinePush CallBackConfig `yaml:"onlinePush"`
|
||||
CallbackBeforeSuperGroupOnlinePush CallBackConfig `yaml:"superGroupOnlinePush"`
|
||||
CallbackBeforeAddFriend CallBackConfig `yaml:"beforeAddFriend"`
|
||||
CallbackBeforeSetFriendRemark CallBackConfig `yaml:"callbackBeforeSetFriendRemark"`
|
||||
CallbackAfterSetFriendRemark CallBackConfig `yaml:"callbackAfterSetFriendRemark"`
|
||||
CallbackBeforeUpdateUserInfo CallBackConfig `yaml:"beforeUpdateUserInfo"`
|
||||
CallbackBeforeUpdateUserInfoEx CallBackConfig `yaml:"beforeUpdateUserInfoEx"`
|
||||
CallbackAfterUpdateUserInfoEx CallBackConfig `yaml:"afterUpdateUserInfoEx"`
|
||||
CallbackBeforeUserRegister CallBackConfig `yaml:"beforeUserRegister"`
|
||||
CallbackAfterUpdateUserInfo CallBackConfig `yaml:"updateUserInfo"`
|
||||
CallbackAfterUserRegister CallBackConfig `yaml:"afterUserRegister"`
|
||||
CallbackBeforeCreateGroup CallBackConfig `yaml:"beforeCreateGroup"`
|
||||
CallbackAfterCreateGroup CallBackConfig `yaml:"afterCreateGroup"`
|
||||
CallbackBeforeMemberJoinGroup CallBackConfig `yaml:"beforeMemberJoinGroup"`
|
||||
CallbackBeforeSetGroupMemberInfo CallBackConfig `yaml:"beforeSetGroupMemberInfo"`
|
||||
CallbackAfterSetGroupMemberInfo CallBackConfig `yaml:"afterSetGroupMemberInfo"`
|
||||
CallbackQuitGroup CallBackConfig `yaml:"quitGroup"`
|
||||
CallbackKillGroupMember CallBackConfig `yaml:"killGroupMember"`
|
||||
CallbackDismissGroup CallBackConfig `yaml:"dismissGroup"`
|
||||
CallbackBeforeJoinGroup CallBackConfig `yaml:"joinGroup"`
|
||||
CallbackAfterTransferGroupOwner CallBackConfig `yaml:"transferGroupOwner"`
|
||||
CallbackBeforeInviteUserToGroup CallBackConfig `yaml:"beforeInviteUserToGroup"`
|
||||
CallbackAfterJoinGroup CallBackConfig `yaml:"joinGroupAfter"`
|
||||
CallbackAfterSetGroupInfo CallBackConfig `yaml:"setGroupInfoAfter"`
|
||||
CallbackBeforeSetGroupInfo CallBackConfig `yaml:"setGroupInfoBefore"`
|
||||
CallbackAfterRevokeMsg CallBackConfig `yaml:"revokeMsgAfter"`
|
||||
CallbackBeforeAddBlack CallBackConfig `yaml:"addBlackBefore"`
|
||||
CallbackAfterAddFriend CallBackConfig `yaml:"addFriendAfter"`
|
||||
CallbackBeforeAddFriendAgree CallBackConfig `yaml:"addFriendAgreeBefore"`
|
||||
|
||||
CallbackAfterDeleteFriend CallBackConfig `yaml:"deleteFriendAfter"`
|
||||
CallbackBeforeImportFriends CallBackConfig `yaml:"importFriendsBefore"`
|
||||
CallbackAfterImportFriends CallBackConfig `yaml:"importFriendsAfter"`
|
||||
CallbackAfterRemoveBlack CallBackConfig `yaml:"removeBlackAfter"`
|
||||
} `yaml:"callback"`
|
||||
|
||||
Prometheus struct {
|
||||
Enable bool `yaml:"enable"`
|
||||
GrafanaUrl string `yaml:"grafanaUrl"`
|
||||
ApiPrometheusPort []int `yaml:"apiPrometheusPort"`
|
||||
UserPrometheusPort []int `yaml:"userPrometheusPort"`
|
||||
FriendPrometheusPort []int `yaml:"friendPrometheusPort"`
|
||||
MessagePrometheusPort []int `yaml:"messagePrometheusPort"`
|
||||
MessageGatewayPrometheusPort []int `yaml:"messageGatewayPrometheusPort"`
|
||||
GroupPrometheusPort []int `yaml:"groupPrometheusPort"`
|
||||
AuthPrometheusPort []int `yaml:"authPrometheusPort"`
|
||||
PushPrometheusPort []int `yaml:"pushPrometheusPort"`
|
||||
ConversationPrometheusPort []int `yaml:"conversationPrometheusPort"`
|
||||
RtcPrometheusPort []int `yaml:"rtcPrometheusPort"`
|
||||
MessageTransferPrometheusPort []int `yaml:"messageTransferPrometheusPort"`
|
||||
ThirdPrometheusPort []int `yaml:"thirdPrometheusPort"`
|
||||
} `yaml:"prometheus"`
|
||||
Notification notification `yaml:"notification"`
|
||||
}
|
||||
|
||||
func NewGlobalConfig() *GlobalConfig {
|
||||
return &GlobalConfig{}
|
||||
}
|
||||
|
||||
type notification struct {
|
||||
GroupCreated NotificationConf `yaml:"groupCreated"`
|
||||
GroupInfoSet NotificationConf `yaml:"groupInfoSet"`
|
||||
JoinGroupApplication NotificationConf `yaml:"joinGroupApplication"`
|
||||
MemberQuit NotificationConf `yaml:"memberQuit"`
|
||||
GroupApplicationAccepted NotificationConf `yaml:"groupApplicationAccepted"`
|
||||
GroupApplicationRejected NotificationConf `yaml:"groupApplicationRejected"`
|
||||
GroupOwnerTransferred NotificationConf `yaml:"groupOwnerTransferred"`
|
||||
MemberKicked NotificationConf `yaml:"memberKicked"`
|
||||
MemberInvited NotificationConf `yaml:"memberInvited"`
|
||||
MemberEnter NotificationConf `yaml:"memberEnter"`
|
||||
GroupDismissed NotificationConf `yaml:"groupDismissed"`
|
||||
GroupMuted NotificationConf `yaml:"groupMuted"`
|
||||
GroupCancelMuted NotificationConf `yaml:"groupCancelMuted"`
|
||||
GroupMemberMuted NotificationConf `yaml:"groupMemberMuted"`
|
||||
GroupMemberCancelMuted NotificationConf `yaml:"groupMemberCancelMuted"`
|
||||
GroupMemberInfoSet NotificationConf `yaml:"groupMemberInfoSet"`
|
||||
GroupMemberSetToAdmin NotificationConf `yaml:"groupMemberSetToAdmin"`
|
||||
GroupMemberSetToOrdinary NotificationConf `yaml:"groupMemberSetToOrdinaryUser"`
|
||||
GroupInfoSetAnnouncement NotificationConf `yaml:"groupInfoSetAnnouncement"`
|
||||
GroupInfoSetName NotificationConf `yaml:"groupInfoSetName"`
|
||||
////////////////////////user///////////////////////
|
||||
UserInfoUpdated NotificationConf `yaml:"userInfoUpdated"`
|
||||
UserStatusChanged NotificationConf `yaml:"userStatusChanged"`
|
||||
//////////////////////friend///////////////////////
|
||||
FriendApplicationAdded NotificationConf `yaml:"friendApplicationAdded"`
|
||||
FriendApplicationApproved NotificationConf `yaml:"friendApplicationApproved"`
|
||||
FriendApplicationRejected NotificationConf `yaml:"friendApplicationRejected"`
|
||||
FriendAdded NotificationConf `yaml:"friendAdded"`
|
||||
FriendDeleted NotificationConf `yaml:"friendDeleted"`
|
||||
FriendRemarkSet NotificationConf `yaml:"friendRemarkSet"`
|
||||
BlackAdded NotificationConf `yaml:"blackAdded"`
|
||||
BlackDeleted NotificationConf `yaml:"blackDeleted"`
|
||||
FriendInfoUpdated NotificationConf `yaml:"friendInfoUpdated"`
|
||||
//////////////////////conversation///////////////////////
|
||||
ConversationChanged NotificationConf `yaml:"conversationChanged"`
|
||||
ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"`
|
||||
type CacheConfig struct {
|
||||
Topic string `mapstructure:"topic"`
|
||||
SlotNum int `mapstructure:"slotNum"`
|
||||
SlotSize int `mapstructure:"slotSize"`
|
||||
SuccessExpire int `mapstructure:"successExpire"`
|
||||
FailedExpire int `mapstructure:"failedExpire"`
|
||||
}
|
||||
|
||||
type LocalCache struct {
|
||||
Topic string `yaml:"topic"`
|
||||
SlotNum int `yaml:"slotNum"`
|
||||
SlotSize int `yaml:"slotSize"`
|
||||
SuccessExpire int `yaml:"successExpire"` // second
|
||||
FailedExpire int `yaml:"failedExpire"` // second
|
||||
User CacheConfig `mapstructure:"user"`
|
||||
Group CacheConfig `mapstructure:"group"`
|
||||
Friend CacheConfig `mapstructure:"friend"`
|
||||
Conversation CacheConfig `mapstructure:"conversation"`
|
||||
}
|
||||
|
||||
func (l LocalCache) Failed() time.Duration {
|
||||
type Log struct {
|
||||
StorageLocation string `mapstructure:"storageLocation"`
|
||||
RotationTime uint `mapstructure:"rotationTime"`
|
||||
RemainRotationCount uint `mapstructure:"remainRotationCount"`
|
||||
RemainLogLevel int `mapstructure:"remainLogLevel"`
|
||||
IsStdout bool `mapstructure:"isStdout"`
|
||||
IsJson bool `mapstructure:"isJson"`
|
||||
WithStack bool `mapstructure:"withStack"`
|
||||
}
|
||||
|
||||
type Minio struct {
|
||||
Bucket string `mapstructure:"bucket"`
|
||||
AccessKeyID string `mapstructure:"accessKeyID"`
|
||||
SecretAccessKey string `mapstructure:"secretAccessKey"`
|
||||
SessionToken string `mapstructure:"sessionToken"`
|
||||
InternalAddress string `mapstructure:"internalAddress"`
|
||||
ExternalAddress string `mapstructure:"externalAddress"`
|
||||
PublicRead bool `mapstructure:"publicRead"`
|
||||
}
|
||||
|
||||
type Mongo struct {
|
||||
URI string `mapstructure:"uri"`
|
||||
Address []string `mapstructure:"address"`
|
||||
Database string `mapstructure:"database"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
MaxPoolSize int `mapstructure:"maxPoolSize"`
|
||||
MaxRetry int `mapstructure:"maxRetry"`
|
||||
}
|
||||
type Kafka struct {
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
ProducerAck string `mapstructure:"producerAck"`
|
||||
CompressType string `mapstructure:"compressType"`
|
||||
Address []string `mapstructure:"address"`
|
||||
ToRedisTopic string `mapstructure:"toRedisTopic"`
|
||||
ToMongoTopic string `mapstructure:"toMongoTopic"`
|
||||
ToPushTopic string `mapstructure:"toPushTopic"`
|
||||
ToRedisGroupID string `mapstructure:"toRedisGroupID"`
|
||||
ToMongoGroupID string `mapstructure:"toMongoGroupID"`
|
||||
ToPushGroupID string `mapstructure:"toPushGroupID"`
|
||||
Tls TLSConfig `mapstructure:"tls"`
|
||||
}
|
||||
type TLSConfig struct {
|
||||
EnableTLS bool `mapstructure:"enableTLS"`
|
||||
CACrt string `mapstructure:"caCrt"`
|
||||
ClientCrt string `mapstructure:"clientCrt"`
|
||||
ClientKey string `mapstructure:"clientKey"`
|
||||
ClientKeyPwd string `mapstructure:"clientKeyPwd"`
|
||||
InsecureSkipVerify bool `mapstructure:"insecureSkipVerify"`
|
||||
}
|
||||
|
||||
type API struct {
|
||||
Api struct {
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"api"`
|
||||
Prometheus struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
GrafanaURL string `mapstructure:"grafanaURL"`
|
||||
} `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type CronTask struct {
|
||||
ChatRecordsClearTime string `mapstructure:"chatRecordsClearTime"`
|
||||
RetainChatRecords int `mapstructure:"retainChatRecords"`
|
||||
}
|
||||
|
||||
type OfflinePushConfig struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Title string `mapstructure:"title"`
|
||||
Desc string `mapstructure:"desc"`
|
||||
Ext string `mapstructure:"ext"`
|
||||
}
|
||||
|
||||
type NotificationConfig struct {
|
||||
IsSendMsg bool `mapstructure:"isSendMsg"`
|
||||
ReliabilityLevel int `mapstructure:"reliabilityLevel"`
|
||||
UnreadCount bool `mapstructure:"unreadCount"`
|
||||
OfflinePush OfflinePushConfig `mapstructure:"offlinePush"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
GroupCreated NotificationConfig `mapstructure:"groupCreated"`
|
||||
GroupInfoSet NotificationConfig `mapstructure:"groupInfoSet"`
|
||||
JoinGroupApplication NotificationConfig `mapstructure:"joinGroupApplication"`
|
||||
MemberQuit NotificationConfig `mapstructure:"memberQuit"`
|
||||
GroupApplicationAccepted NotificationConfig `mapstructure:"groupApplicationAccepted"`
|
||||
GroupApplicationRejected NotificationConfig `mapstructure:"groupApplicationRejected"`
|
||||
GroupOwnerTransferred NotificationConfig `mapstructure:"groupOwnerTransferred"`
|
||||
MemberKicked NotificationConfig `mapstructure:"memberKicked"`
|
||||
MemberInvited NotificationConfig `mapstructure:"memberInvited"`
|
||||
MemberEnter NotificationConfig `mapstructure:"memberEnter"`
|
||||
GroupDismissed NotificationConfig `mapstructure:"groupDismissed"`
|
||||
GroupMuted NotificationConfig `mapstructure:"groupMuted"`
|
||||
GroupCancelMuted NotificationConfig `mapstructure:"groupCancelMuted"`
|
||||
GroupMemberMuted NotificationConfig `mapstructure:"groupMemberMuted"`
|
||||
GroupMemberCancelMuted NotificationConfig `mapstructure:"groupMemberCancelMuted"`
|
||||
GroupMemberInfoSet NotificationConfig `mapstructure:"groupMemberInfoSet"`
|
||||
GroupMemberSetToAdmin NotificationConfig `yaml:"groupMemberSetToAdmin"`
|
||||
GroupMemberSetToOrdinary NotificationConfig `yaml:"groupMemberSetToOrdinaryUser"`
|
||||
GroupInfoSetAnnouncement NotificationConfig `mapstructure:"groupInfoSetAnnouncement"`
|
||||
GroupInfoSetName NotificationConfig `mapstructure:"groupInfoSetName"`
|
||||
FriendApplicationAdded NotificationConfig `mapstructure:"friendApplicationAdded"`
|
||||
FriendApplicationApproved NotificationConfig `mapstructure:"friendApplicationApproved"`
|
||||
FriendApplicationRejected NotificationConfig `mapstructure:"friendApplicationRejected"`
|
||||
FriendAdded NotificationConfig `mapstructure:"friendAdded"`
|
||||
FriendDeleted NotificationConfig `mapstructure:"friendDeleted"`
|
||||
FriendRemarkSet NotificationConfig `mapstructure:"friendRemarkSet"`
|
||||
BlackAdded NotificationConfig `mapstructure:"blackAdded"`
|
||||
BlackDeleted NotificationConfig `mapstructure:"blackDeleted"`
|
||||
FriendInfoUpdated NotificationConfig `mapstructure:"friendInfoUpdated"`
|
||||
UserInfoUpdated NotificationConfig `mapstructure:"userInfoUpdated"`
|
||||
UserStatusChanged NotificationConfig `mapstructure:"userStatusChanged"`
|
||||
ConversationChanged NotificationConfig `mapstructure:"conversationChanged"`
|
||||
ConversationSetPrivate NotificationConfig `mapstructure:"conversationSetPrivate"`
|
||||
}
|
||||
|
||||
type Prometheus struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
}
|
||||
|
||||
type MsgGateway struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
LongConnSvr struct {
|
||||
Ports []int `mapstructure:"ports"`
|
||||
WebsocketMaxConnNum int `mapstructure:"websocketMaxConnNum"`
|
||||
WebsocketMaxMsgLen int `mapstructure:"websocketMaxMsgLen"`
|
||||
WebsocketTimeout int `mapstructure:"websocketTimeout"`
|
||||
} `mapstructure:"longConnSvr"`
|
||||
MultiLoginPolicy int `mapstructure:"multiLoginPolicy"`
|
||||
}
|
||||
|
||||
type MsgTransfer struct {
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type Push struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
MaxConcurrentWorkers int `mapstructure:"maxConcurrentWorkers"`
|
||||
Enable string `mapstructure:"enable"`
|
||||
GeTui struct {
|
||||
PushUrl string `mapstructure:"pushUrl"`
|
||||
MasterSecret string `mapstructure:"masterSecret"`
|
||||
AppKey string `mapstructure:"appKey"`
|
||||
Intent string `mapstructure:"intent"`
|
||||
ChannelID string `mapstructure:"channelID"`
|
||||
ChannelName string `mapstructure:"channelName"`
|
||||
} `mapstructure:"geTui"`
|
||||
FCM struct {
|
||||
ServiceAccount string `mapstructure:"serviceAccount"`
|
||||
} `mapstructure:"fcm"`
|
||||
JPNS struct {
|
||||
AppKey string `mapstructure:"appKey"`
|
||||
MasterSecret string `mapstructure:"masterSecret"`
|
||||
PushURL string `mapstructure:"pushURL"`
|
||||
PushIntent string `mapstructure:"pushIntent"`
|
||||
} `mapstructure:"jpns"`
|
||||
IOSPush struct {
|
||||
PushSound string `mapstructure:"pushSound"`
|
||||
BadgeCount bool `mapstructure:"badgeCount"`
|
||||
Production bool `mapstructure:"production"`
|
||||
} `mapstructure:"iosPush"`
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
TokenPolicy struct {
|
||||
Expire int64 `mapstructure:"expire"`
|
||||
} `mapstructure:"tokenPolicy"`
|
||||
}
|
||||
|
||||
type Conversation struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type Friend struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
FriendVerify bool `mapstructure:"friendVerify"`
|
||||
}
|
||||
|
||||
type Third struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
Object struct {
|
||||
Enable string `mapstructure:"enable"`
|
||||
Cos Cos `mapstructure:"cos"`
|
||||
Oss Oss `mapstructure:"oss"`
|
||||
Kodo struct {
|
||||
Endpoint string `mapstructure:"endpoint"`
|
||||
Bucket string `mapstructure:"bucket"`
|
||||
BucketURL string `mapstructure:"bucketURL"`
|
||||
AccessKeyID string `mapstructure:"accessKeyID"`
|
||||
AccessKeySecret string `mapstructure:"accessKeySecret"`
|
||||
SessionToken string `mapstructure:"sessionToken"`
|
||||
PublicRead bool `mapstructure:"publicRead"`
|
||||
} `mapstructure:"kodo"`
|
||||
Aws struct {
|
||||
Endpoint string `mapstructure:"endpoint"`
|
||||
Region string `mapstructure:"region"`
|
||||
Bucket string `mapstructure:"bucket"`
|
||||
AccessKeyID string `mapstructure:"accessKeyID"`
|
||||
AccessKeySecret string `mapstructure:"accessKeySecret"`
|
||||
PublicRead bool `mapstructure:"publicRead"`
|
||||
} `mapstructure:"aws"`
|
||||
} `mapstructure:"object"`
|
||||
}
|
||||
type Cos struct {
|
||||
BucketURL string `mapstructure:"bucketURL"`
|
||||
SecretID string `mapstructure:"secretID"`
|
||||
SecretKey string `mapstructure:"secretKey"`
|
||||
SessionToken string `mapstructure:"sessionToken"`
|
||||
PublicRead bool `mapstructure:"publicRead"`
|
||||
}
|
||||
type Oss struct {
|
||||
Endpoint string `mapstructure:"endpoint"`
|
||||
Bucket string `mapstructure:"bucket"`
|
||||
BucketURL string `mapstructure:"bucketURL"`
|
||||
AccessKeyID string `mapstructure:"accessKeyID"`
|
||||
AccessKeySecret string `mapstructure:"accessKeySecret"`
|
||||
SessionToken string `mapstructure:"sessionToken"`
|
||||
PublicRead bool `mapstructure:"publicRead"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
RPC struct {
|
||||
RegisterIP string `mapstructure:"registerIP"`
|
||||
ListenIP string `mapstructure:"listenIP"`
|
||||
Ports []int `mapstructure:"ports"`
|
||||
} `mapstructure:"rpc"`
|
||||
Prometheus Prometheus `mapstructure:"prometheus"`
|
||||
}
|
||||
|
||||
type Redis struct {
|
||||
Address []string `mapstructure:"address"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
EnablePipeline bool `mapstructure:"enablePipeline"`
|
||||
ClusterMode bool `mapstructure:"clusterMode"`
|
||||
DB int `mapstructure:"db"`
|
||||
MaxRetry int `mapstructure:"MaxRetry"`
|
||||
}
|
||||
|
||||
type BeforeConfig struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Timeout int `mapstructure:"timeout"`
|
||||
FailedContinue bool `mapstructure:"failedContinue"`
|
||||
}
|
||||
|
||||
type AfterConfig struct {
|
||||
Enable bool `mapstructure:"enable"`
|
||||
Timeout int `mapstructure:"timeout"`
|
||||
}
|
||||
|
||||
type Share struct {
|
||||
Secret string `mapstructure:"secret"`
|
||||
Env string `mapstructure:"env"`
|
||||
RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"`
|
||||
IMAdminUserID []string `mapstructure:"imAdminUserID"`
|
||||
}
|
||||
type RpcRegisterName struct {
|
||||
User string `mapstructure:"user"`
|
||||
Friend string `mapstructure:"friend"`
|
||||
Msg string `mapstructure:"msg"`
|
||||
Push string `mapstructure:"push"`
|
||||
MessageGateway string `mapstructure:"messageGateway"`
|
||||
Group string `mapstructure:"group"`
|
||||
Auth string `mapstructure:"auth"`
|
||||
Conversation string `mapstructure:"conversation"`
|
||||
Third string `mapstructure:"third"`
|
||||
}
|
||||
|
||||
func (r *RpcRegisterName) GetServiceNames() []string {
|
||||
return []string{
|
||||
r.User,
|
||||
r.Friend,
|
||||
r.Msg,
|
||||
r.Push,
|
||||
r.MessageGateway,
|
||||
r.Group,
|
||||
r.Auth,
|
||||
r.Conversation,
|
||||
r.Third,
|
||||
}
|
||||
}
|
||||
|
||||
// FullConfig stores all configurations for before and after events
|
||||
type Webhooks struct {
|
||||
URL string `mapstructure:"url"`
|
||||
BeforeSendSingleMsg BeforeConfig `mapstructure:"beforeSendSingleMsg"`
|
||||
BeforeUpdateUserInfoEx BeforeConfig `mapstructure:"beforeUpdateUserInfoEx"`
|
||||
AfterUpdateUserInfoEx AfterConfig `mapstructure:"afterUpdateUserInfoEx"`
|
||||
AfterSendSingleMsg AfterConfig `mapstructure:"afterSendSingleMsg"`
|
||||
BeforeSendGroupMsg BeforeConfig `mapstructure:"beforeSendGroupMsg"`
|
||||
BeforeMsgModify BeforeConfig `mapstructure:"beforeMsgModify"`
|
||||
AfterSendGroupMsg AfterConfig `mapstructure:"afterSendGroupMsg"`
|
||||
AfterUserOnline AfterConfig `mapstructure:"afterUserOnline"`
|
||||
AfterUserOffline AfterConfig `mapstructure:"afterUserOffline"`
|
||||
AfterUserKickOff AfterConfig `mapstructure:"afterUserKickOff"`
|
||||
BeforeOfflinePush BeforeConfig `mapstructure:"beforeOfflinePush"`
|
||||
BeforeOnlinePush BeforeConfig `mapstructure:"beforeOnlinePush"`
|
||||
BeforeGroupOnlinePush BeforeConfig `mapstructure:"beforeGroupOnlinePush"`
|
||||
BeforeAddFriend BeforeConfig `mapstructure:"beforeAddFriend"`
|
||||
BeforeUpdateUserInfo BeforeConfig `mapstructure:"beforeUpdateUserInfo"`
|
||||
AfterUpdateUserInfo AfterConfig `mapstructure:"afterUpdateUserInfo"`
|
||||
BeforeCreateGroup BeforeConfig `mapstructure:"beforeCreateGroup"`
|
||||
AfterCreateGroup AfterConfig `mapstructure:"afterCreateGroup"`
|
||||
BeforeMemberJoinGroup BeforeConfig `mapstructure:"beforeMemberJoinGroup"`
|
||||
BeforeSetGroupMemberInfo BeforeConfig `mapstructure:"beforeSetGroupMemberInfo"`
|
||||
AfterSetGroupMemberInfo AfterConfig `mapstructure:"afterSetGroupMemberInfo"`
|
||||
AfterQuitGroup AfterConfig `mapstructure:"afterQuitGroup"`
|
||||
AfterKickGroupMember AfterConfig `mapstructure:"afterKickGroupMember"`
|
||||
AfterDismissGroup AfterConfig `mapstructure:"afterDismissGroup"`
|
||||
BeforeApplyJoinGroup BeforeConfig `mapstructure:"beforeApplyJoinGroup"`
|
||||
AfterGroupMsgRead AfterConfig `mapstructure:"afterGroupMsgRead"`
|
||||
AfterSingleMsgRead AfterConfig `mapstructure:"afterSingleMsgRead"`
|
||||
BeforeUserRegister BeforeConfig `mapstructure:"beforeUserRegister"`
|
||||
AfterUserRegister AfterConfig `mapstructure:"afterUserRegister"`
|
||||
AfterTransferGroupOwner AfterConfig `mapstructure:"afterTransferGroupOwner"`
|
||||
BeforeSetFriendRemark BeforeConfig `mapstructure:"beforeSetFriendRemark"`
|
||||
AfterSetFriendRemark AfterConfig `mapstructure:"afterSetFriendRemark"`
|
||||
AfterGroupMsgRevoke AfterConfig `mapstructure:"afterGroupMsgRevoke"`
|
||||
AfterJoinGroup AfterConfig `mapstructure:"afterJoinGroup"`
|
||||
BeforeInviteUserToGroup BeforeConfig `mapstructure:"beforeInviteUserToGroup"`
|
||||
AfterSetGroupInfo AfterConfig `mapstructure:"afterSetGroupInfo"`
|
||||
BeforeSetGroupInfo BeforeConfig `mapstructure:"beforeSetGroupInfo"`
|
||||
AfterRevokeMsg AfterConfig `mapstructure:"afterRevokeMsg"`
|
||||
BeforeAddBlack BeforeConfig `mapstructure:"beforeAddBlack"`
|
||||
AfterAddFriend AfterConfig `mapstructure:"afterAddFriend"`
|
||||
BeforeAddFriendAgree BeforeConfig `mapstructure:"beforeAddFriendAgree"`
|
||||
AfterDeleteFriend AfterConfig `mapstructure:"afterDeleteFriend"`
|
||||
BeforeImportFriends BeforeConfig `mapstructure:"beforeImportFriends"`
|
||||
AfterImportFriends AfterConfig `mapstructure:"afterImportFriends"`
|
||||
AfterRemoveBlack AfterConfig `mapstructure:"afterRemoveBlack"`
|
||||
}
|
||||
|
||||
type ZooKeeper struct {
|
||||
Schema string `mapstructure:"schema"`
|
||||
Address []string `mapstructure:"address"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
}
|
||||
|
||||
func (m *Mongo) Build() *mongoutil.Config {
|
||||
return &mongoutil.Config{
|
||||
Uri: m.URI,
|
||||
Address: m.Address,
|
||||
Database: m.Database,
|
||||
Username: m.Username,
|
||||
Password: m.Password,
|
||||
MaxPoolSize: m.MaxPoolSize,
|
||||
MaxRetry: m.MaxRetry,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Redis) Build() *redisutil.Config {
|
||||
return &redisutil.Config{
|
||||
ClusterMode: r.ClusterMode,
|
||||
Address: r.Address,
|
||||
Username: r.Username,
|
||||
Password: r.Password,
|
||||
DB: r.DB,
|
||||
MaxRetry: r.MaxRetry,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Kafka) Build() *kafka.Config {
|
||||
return &kafka.Config{
|
||||
Username: k.Username,
|
||||
Password: k.Password,
|
||||
ProducerAck: k.ProducerAck,
|
||||
CompressType: k.CompressType,
|
||||
Addr: k.Address,
|
||||
TLS: kafka.TLSConfig{
|
||||
EnableTLS: k.Tls.EnableTLS,
|
||||
CACrt: k.Tls.CACrt,
|
||||
ClientCrt: k.Tls.ClientCrt,
|
||||
ClientKey: k.Tls.ClientKey,
|
||||
ClientKeyPwd: k.Tls.ClientKeyPwd,
|
||||
InsecureSkipVerify: k.Tls.InsecureSkipVerify,
|
||||
},
|
||||
}
|
||||
}
|
||||
func (m *Minio) Build() *minio.Config {
|
||||
conf := minio.Config{
|
||||
Bucket: m.Bucket,
|
||||
AccessKeyID: m.AccessKeyID,
|
||||
SecretAccessKey: m.SecretAccessKey,
|
||||
SessionToken: m.SessionToken,
|
||||
PublicRead: m.PublicRead,
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(m.InternalAddress); err == nil {
|
||||
conf.Endpoint = fmt.Sprintf("http://%s", m.InternalAddress)
|
||||
} else {
|
||||
conf.Endpoint = m.InternalAddress
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(m.ExternalAddress); err == nil {
|
||||
conf.SignEndpoint = fmt.Sprintf("http://%s", m.ExternalAddress)
|
||||
} else {
|
||||
conf.SignEndpoint = m.ExternalAddress
|
||||
}
|
||||
return &conf
|
||||
}
|
||||
func (c *Cos) Build() *cos.Config {
|
||||
return &cos.Config{
|
||||
BucketURL: c.BucketURL,
|
||||
SecretID: c.SecretID,
|
||||
SecretKey: c.SecretKey,
|
||||
SessionToken: c.SessionToken,
|
||||
PublicRead: c.PublicRead,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Oss) Build() *oss.Config {
|
||||
return &oss.Config{
|
||||
Endpoint: o.Endpoint,
|
||||
Bucket: o.Bucket,
|
||||
BucketURL: o.BucketURL,
|
||||
AccessKeyID: o.AccessKeyID,
|
||||
AccessKeySecret: o.AccessKeySecret,
|
||||
SessionToken: o.SessionToken,
|
||||
PublicRead: o.PublicRead,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CacheConfig) Failed() time.Duration {
|
||||
return time.Second * time.Duration(l.FailedExpire)
|
||||
}
|
||||
|
||||
func (l LocalCache) Success() time.Duration {
|
||||
func (l *CacheConfig) Success() time.Duration {
|
||||
return time.Second * time.Duration(l.SuccessExpire)
|
||||
}
|
||||
|
||||
func (l LocalCache) Enable() bool {
|
||||
func (l *CacheConfig) Enable() bool {
|
||||
return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0
|
||||
}
|
||||
|
||||
type localCache struct {
|
||||
User LocalCache `yaml:"user"`
|
||||
Group LocalCache `yaml:"group"`
|
||||
Friend LocalCache `yaml:"friend"`
|
||||
Conversation LocalCache `yaml:"conversation"`
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) GetServiceNames() []string {
|
||||
return []string{
|
||||
c.RpcRegisterName.OpenImUserName,
|
||||
c.RpcRegisterName.OpenImFriendName,
|
||||
c.RpcRegisterName.OpenImMsgName,
|
||||
c.RpcRegisterName.OpenImPushName,
|
||||
c.RpcRegisterName.OpenImMessageGatewayName,
|
||||
c.RpcRegisterName.OpenImGroupName,
|
||||
c.RpcRegisterName.OpenImAuthName,
|
||||
c.RpcRegisterName.OpenImConversationName,
|
||||
c.RpcRegisterName.OpenImThirdName,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error {
|
||||
data, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return registry.RegisterConf2Registry(ConfKey, data)
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) {
|
||||
return registry.GetConfFromRegistry(ConfKey)
|
||||
}
|
||||
|
||||
func (c *GlobalConfig) EncodeConfig() []byte {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if err := yaml.NewEncoder(buf).Encode(c); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright © 2024 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 config
|
||||
|
||||
const ConfKey = "conf"
|
||||
|
||||
const (
|
||||
// DefaultDirPerm is used for creating general directories, allowing the owner to read, write, and execute,
|
||||
// while the group and others can only read and execute.
|
||||
DefaultDirPerm = 0755
|
||||
|
||||
// PrivateFilePerm is used for sensitive files, allowing only the owner to read and write.
|
||||
PrivateFilePerm = 0600
|
||||
|
||||
// ExecFilePerm is used for executable files, allowing the owner to read, write, and execute,
|
||||
// while the group and others can only read.
|
||||
ExecFilePerm = 0754
|
||||
|
||||
// SharedDirPerm is used for shared directories, allowing the owner and group to read, write, and execute,
|
||||
// with no permissions for others.
|
||||
SharedDirPerm = 0770
|
||||
|
||||
// ReadOnlyDirPerm is used for read-only directories, allowing the owner, group, and others to only read.
|
||||
ReadOnlyDirPerm = 0555
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/spf13/viper"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func LoadConfig(path string, envPrefix string, config any) error {
|
||||
v := viper.New()
|
||||
v.SetConfigFile(path)
|
||||
v.SetEnvPrefix(envPrefix)
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return errs.WrapMsg(err, "failed to read config file", "path", path, "envPrefix", envPrefix)
|
||||
}
|
||||
|
||||
if err := v.Unmarshal(config, func(config *mapstructure.DecoderConfig) {
|
||||
config.TagName = "mapstructure"
|
||||
}); err != nil {
|
||||
return errs.WrapMsg(err, "failed to unmarshal config", "path", path, "envPrefix", envPrefix)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadLogConfig(t *testing.T) {
|
||||
var log Log
|
||||
err := LoadConfig("../../../config/log.yml", "IMENV_LOG", &log)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "../../../../logs/", log.StorageLocation)
|
||||
}
|
||||
|
||||
func TestLoadMinioConfig(t *testing.T) {
|
||||
var storageConfig Minio
|
||||
err := LoadConfig("../../../config/minio.yml", "IMENV_MINIO", &storageConfig)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "openim", storageConfig.Bucket)
|
||||
}
|
||||
|
||||
func TestLoadWebhooksConfig(t *testing.T) {
|
||||
var webhooks Webhooks
|
||||
err := LoadConfig("../../../config/webhooks.yml", "IMENV_WEBHOOKS", &webhooks)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, webhooks.BeforeAddBlack.Timeout)
|
||||
|
||||
}
|
||||
|
||||
func TestLoadOpenIMRpcUserConfig(t *testing.T) {
|
||||
var user User
|
||||
err := LoadConfig("../../../config/openim-rpc-user.yml", "IMENV_OPENIM_RPC_USER", &user)
|
||||
assert.Nil(t, err)
|
||||
//export IMENV_OPENIM_RPC_USER_RPC_LISTENIP="0.0.0.0"
|
||||
assert.Equal(t, "0.0.0.0", user.RPC.ListenIP)
|
||||
//export IMENV_OPENIM_RPC_USER_RPC_PORTS="10110,10111,10112"
|
||||
assert.Equal(t, []int{10110, 10111, 10112}, user.RPC.Ports)
|
||||
}
|
||||
+26
-44
@@ -16,15 +16,14 @@ package config
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/field"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
//go:embed version
|
||||
@@ -37,34 +36,33 @@ const (
|
||||
)
|
||||
|
||||
// return absolude path join ../config/, this is k8s container config path.
|
||||
func GetDefaultConfigPath() string {
|
||||
func GetDefaultConfigPath() (string, error) {
|
||||
executablePath, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println("GetDefaultConfigPath error:", err.Error())
|
||||
return ""
|
||||
return "", errs.WrapMsg(err, "failed to get executable path")
|
||||
}
|
||||
|
||||
configPath, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/"))
|
||||
configPath, err := field.OutDir(filepath.Join(filepath.Dir(executablePath), "../config/"))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
return "", errs.WrapMsg(err, "failed to get output directory", "outDir", filepath.Join(filepath.Dir(executablePath), "../config/"))
|
||||
}
|
||||
return configPath
|
||||
return configPath, nil
|
||||
}
|
||||
|
||||
// getProjectRoot returns the absolute path of the project root directory.
|
||||
func GetProjectRoot() string {
|
||||
executablePath, _ := os.Executable()
|
||||
|
||||
projectRoot, err := genutil.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../.."))
|
||||
func GetProjectRoot() (string, error) {
|
||||
executablePath, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to get output directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
return "", errs.Wrap(err)
|
||||
}
|
||||
return projectRoot
|
||||
projectRoot, err := field.OutDir(filepath.Join(filepath.Dir(executablePath), "../../../../.."))
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err)
|
||||
}
|
||||
return projectRoot, nil
|
||||
}
|
||||
|
||||
func GetOptionsByNotification(cfg NotificationConf) msgprocessor.Options {
|
||||
func GetOptionsByNotification(cfg NotificationConfig) msgprocessor.Options {
|
||||
opts := msgprocessor.NewOptions()
|
||||
|
||||
if cfg.UnreadCount {
|
||||
@@ -91,37 +89,21 @@ func initConfig(config any, configName, configFolderPath string) error {
|
||||
_, err := os.Stat(configFolderPath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
fmt.Println("stat config path error:", err.Error())
|
||||
return fmt.Errorf("stat config path error: %w", err)
|
||||
return errs.WrapMsg(err, "stat config path error", "config Folder Path", configFolderPath)
|
||||
}
|
||||
configFolderPath = filepath.Join(GetProjectRoot(), "config", configName)
|
||||
fmt.Println("flag's path,enviment's path,default path all is not exist,using project path:", configFolderPath)
|
||||
path, err := GetProjectRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configFolderPath = filepath.Join(path, "config", configName)
|
||||
}
|
||||
data, err := os.ReadFile(configFolderPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read file error: %w", err)
|
||||
return errs.WrapMsg(err, "read file error", "config Folder Path", configFolderPath)
|
||||
}
|
||||
if err = yaml.Unmarshal(data, config); err != nil {
|
||||
return fmt.Errorf("unmarshal yaml error: %w", err)
|
||||
return errs.WrapMsg(err, "unmarshal yaml error", "config Folder Path", configFolderPath)
|
||||
}
|
||||
fmt.Println("The path of the configuration file to start the process:", configFolderPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitConfig(config *GlobalConfig, configFolderPath string) error {
|
||||
if configFolderPath == "" {
|
||||
envConfigPath := os.Getenv("OPENIMCONFIG")
|
||||
if envConfigPath != "" {
|
||||
configFolderPath = envConfigPath
|
||||
} else {
|
||||
configFolderPath = GetDefaultConfigPath()
|
||||
}
|
||||
}
|
||||
|
||||
if err := initConfig(config, FileName, configFolderPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return initConfig(&config.Notification, NotificationFileName, configFolderPath)
|
||||
}
|
||||
|
||||
@@ -1,131 +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 config
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
)
|
||||
|
||||
func TestGetDefaultConfigPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got, _ := GetDefaultConfigPath(); got != tt.want {
|
||||
t.Errorf("GetDefaultConfigPath() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProjectRoot(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got, _ := GetProjectRoot(); got != tt.want {
|
||||
t.Errorf("GetProjectRoot() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOptionsByNotification(t *testing.T) {
|
||||
type args struct {
|
||||
cfg NotificationConf
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want msgprocessor.Options
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetOptionsByNotification(tt.args.cfg); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetOptionsByNotification() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_initConfig(t *testing.T) {
|
||||
type args struct {
|
||||
config any
|
||||
configName string
|
||||
configFolderPath string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := initConfig(tt.args.config, tt.args.configName, tt.args.configFolderPath); (err != nil) != tt.wantErr {
|
||||
t.Errorf("initConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitConfig(t *testing.T) {
|
||||
type args struct {
|
||||
configFolderPath string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
config *GlobalConfig
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := InitConfig(tt.config, tt.args.configFolderPath); (err != nil) != tt.wantErr {
|
||||
t.Errorf("InitConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
Config.LocalCache.Friend.Topic = "friend"
|
||||
Config.LocalCache.Friend.SlotNum = 500
|
||||
Config.LocalCache.Friend.SlotSize = 20000
|
||||
|
||||
data, _ := yaml.Marshal(&Config)
|
||||
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
3.6.0
|
||||
3.7.0
|
||||
@@ -17,9 +17,9 @@ package convert
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
sdk "github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
sdk "github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
func BlackDB2Pb(ctx context.Context, blackDBs []*relation.BlackModel, f func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (blackPbs []*sdk.BlackInfo, err error) {
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/OpenIMSDK/protocol/conversation"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/conversation"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation.Conversation {
|
||||
conversationPB := &conversation.Conversation{}
|
||||
conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.Unix()
|
||||
if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil {
|
||||
if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil {
|
||||
return nil
|
||||
}
|
||||
return conversationPB
|
||||
@@ -32,7 +32,7 @@ func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation
|
||||
func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversationsPB []*conversation.Conversation) {
|
||||
for _, conversationDB := range conversationsDB {
|
||||
conversationPB := &conversation.Conversation{}
|
||||
if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil {
|
||||
if err := datautil.CopyStructFields(conversationPB, conversationDB); err != nil {
|
||||
continue
|
||||
}
|
||||
conversationPB.LatestMsgDestructTime = conversationDB.LatestMsgDestructTime.Unix()
|
||||
@@ -43,7 +43,7 @@ func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversa
|
||||
|
||||
func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.ConversationModel {
|
||||
conversationDB := &relation.ConversationModel{}
|
||||
if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil {
|
||||
if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil {
|
||||
return nil
|
||||
}
|
||||
return conversationDB
|
||||
@@ -52,7 +52,7 @@ func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.Conv
|
||||
func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*relation.ConversationModel) {
|
||||
for _, conversationPB := range conversationsPB {
|
||||
conversationDB := &relation.ConversationModel{}
|
||||
if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil {
|
||||
if err := datautil.CopyStructFields(conversationDB, conversationPB); err != nil {
|
||||
continue
|
||||
}
|
||||
conversationsDB = append(conversationsDB, conversationDB)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -18,19 +18,20 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/timeutil"
|
||||
)
|
||||
|
||||
func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel {
|
||||
dbFriend := &relation.FriendModel{}
|
||||
err := utils.CopyStructFields(dbFriend, friend)
|
||||
err := datautil.CopyStructFields(dbFriend, friend)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
dbFriend.FriendUserID = friend.FriendUser.UserID
|
||||
dbFriend.CreateTime = utils.UnixSecondToTime(friend.CreateTime)
|
||||
dbFriend.CreateTime = timeutil.UnixSecondToTime(friend.CreateTime)
|
||||
return dbFriend
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ func FriendsDB2Pb(
|
||||
}
|
||||
for _, friend := range friendsDB {
|
||||
friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}}
|
||||
err := utils.CopyStructFields(friendPb, friend)
|
||||
err := datautil.CopyStructFields(friendPb, friend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -88,10 +89,7 @@ func FriendsDB2Pb(
|
||||
|
||||
}
|
||||
|
||||
func FriendRequestDB2Pb(ctx context.Context,
|
||||
friendRequests []*relation.FriendRequestModel,
|
||||
getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error),
|
||||
) ([]*sdkws.FriendRequest, error) {
|
||||
func FriendRequestDB2Pb(ctx context.Context, friendRequests []*relation.FriendRequestModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) {
|
||||
if len(friendRequests) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -100,7 +98,7 @@ func FriendRequestDB2Pb(ctx context.Context,
|
||||
userIDMap[friendRequest.ToUserID] = struct{}{}
|
||||
userIDMap[friendRequest.FromUserID] = struct{}{}
|
||||
}
|
||||
users, err := getUsers(ctx, utils.Keys(userIDMap))
|
||||
users, err := getUsers(ctx, datautil.Keys(userIDMap))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ package convert
|
||||
import (
|
||||
"time"
|
||||
|
||||
pbgroup "github.com/OpenIMSDK/protocol/group"
|
||||
sdkws "github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
pbgroup "github.com/openimsdk/protocol/group"
|
||||
sdkws "github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
func Db2PbGroupInfo(m *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
|
||||
@@ -55,12 +55,7 @@ func Pb2DbGroupRequest(req *pbgroup.GroupApplicationResponseReq, handleUserID st
|
||||
}
|
||||
}
|
||||
|
||||
func Db2PbCMSGroup(
|
||||
m *relation.GroupModel,
|
||||
ownerUserID string,
|
||||
ownerUserName string,
|
||||
memberCount uint32,
|
||||
) *pbgroup.CMSGroup {
|
||||
func Db2PbCMSGroup(m *relation.GroupModel, ownerUserID string, ownerUserName string, memberCount uint32) *pbgroup.CMSGroup {
|
||||
return &pbgroup.CMSGroup{
|
||||
GroupInfo: Db2PbGroupInfo(m, ownerUserID, memberCount),
|
||||
GroupOwnerUserID: ownerUserID,
|
||||
@@ -85,11 +80,7 @@ func Db2PbGroupMember(m *relation.GroupMemberModel) *sdkws.GroupMemberFullInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func Db2PbGroupRequest(
|
||||
m *relation.GroupRequestModel,
|
||||
user *sdkws.PublicUserInfo,
|
||||
group *sdkws.GroupInfo,
|
||||
) *sdkws.GroupRequest {
|
||||
func Db2PbGroupRequest(m *relation.GroupRequestModel, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest {
|
||||
return &sdkws.GroupRequest{
|
||||
UserInfo: user,
|
||||
GroupInfo: group,
|
||||
@@ -137,7 +128,7 @@ func Pb2DBGroupInfo(m *sdkws.GroupInfo) *relation.GroupModel {
|
||||
}
|
||||
}
|
||||
|
||||
//func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel {
|
||||
// func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel {
|
||||
// return &relation.GroupMemberModel{
|
||||
// UserID: m.UserID,
|
||||
// Nickname: m.Nickname,
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel {
|
||||
func MsgPb2DB(msg *sdkws.MsgData) *relation.MsgDataModel {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
var msgDataModel unrelation.MsgDataModel
|
||||
var msgDataModel relation.MsgDataModel
|
||||
msgDataModel.SendID = msg.SendID
|
||||
msgDataModel.RecvID = msg.RecvID
|
||||
msgDataModel.GroupID = msg.GroupID
|
||||
@@ -43,7 +43,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel {
|
||||
msgDataModel.Status = msg.Status
|
||||
msgDataModel.Options = msg.Options
|
||||
if msg.OfflinePushInfo != nil {
|
||||
msgDataModel.OfflinePush = &unrelation.OfflinePushModel{
|
||||
msgDataModel.OfflinePush = &relation.OfflinePushModel{
|
||||
Title: msg.OfflinePushInfo.Title,
|
||||
Desc: msg.OfflinePushInfo.Desc,
|
||||
Ex: msg.OfflinePushInfo.Ex,
|
||||
@@ -57,7 +57,7 @@ func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel {
|
||||
return &msgDataModel
|
||||
}
|
||||
|
||||
func MsgDB2Pb(msgModel *unrelation.MsgDataModel) *sdkws.MsgData {
|
||||
func MsgDB2Pb(msgModel *relation.MsgDataModel) *sdkws.MsgData {
|
||||
if msgModel == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ package convert
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
func UsersDB2Pb(users []*relationtb.UserModel) []*sdkws.UserInfo {
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
)
|
||||
|
||||
Vendored
+3
-3
@@ -18,11 +18,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
@@ -48,10 +48,10 @@ type BlackCacheRedis struct {
|
||||
blackDB relationtb.BlackModelInterface
|
||||
}
|
||||
|
||||
func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache {
|
||||
func NewBlackCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache {
|
||||
rcClient := rockscache.NewClient(rdb, options)
|
||||
mc := NewMetaCacheRedis(rcClient)
|
||||
b := config.Config.LocalCache.Friend
|
||||
b := localCache.Friend
|
||||
log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable())
|
||||
mc.SetTopic(b.Topic)
|
||||
mc.SetRawRedisClient(rdb)
|
||||
|
||||
Vendored
+12
-9
@@ -27,29 +27,26 @@ var (
|
||||
subscribe map[string][]string
|
||||
)
|
||||
|
||||
func getPublishKey(topic string, key []string) []string {
|
||||
if topic == "" || len(key) == 0 {
|
||||
return nil
|
||||
}
|
||||
func InitLocalCache(localCache *config.LocalCache) {
|
||||
once.Do(func() {
|
||||
list := []struct {
|
||||
Local config.LocalCache
|
||||
Local config.CacheConfig
|
||||
Keys []string
|
||||
}{
|
||||
{
|
||||
Local: config.Config.LocalCache.User,
|
||||
Local: localCache.User,
|
||||
Keys: []string{cachekey.UserInfoKey, cachekey.UserGlobalRecvMsgOptKey},
|
||||
},
|
||||
{
|
||||
Local: config.Config.LocalCache.Group,
|
||||
Local: localCache.Group,
|
||||
Keys: []string{cachekey.GroupMemberIDsKey, cachekey.GroupInfoKey, cachekey.GroupMemberInfoKey},
|
||||
},
|
||||
{
|
||||
Local: config.Config.LocalCache.Friend,
|
||||
Local: localCache.Friend,
|
||||
Keys: []string{cachekey.FriendIDsKey, cachekey.BlackIDsKey},
|
||||
},
|
||||
{
|
||||
Local: config.Config.LocalCache.Conversation,
|
||||
Local: localCache.Conversation,
|
||||
Keys: []string{cachekey.ConversationKey, cachekey.ConversationIDsKey, cachekey.ConversationNotReceiveMessageUserIDsKey},
|
||||
},
|
||||
}
|
||||
@@ -60,6 +57,12 @@ func getPublishKey(topic string, key []string) []string {
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getPublishKey(topic string, key []string) []string {
|
||||
if topic == "" || len(key) == 0 {
|
||||
return nil
|
||||
}
|
||||
prefix, ok := subscribe[topic]
|
||||
if !ok {
|
||||
return nil
|
||||
|
||||
Vendored
+29
-52
@@ -20,24 +20,25 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/encrypt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
//conversationKey = "CONVERSATION:"
|
||||
//conversationIDsKey = "CONVERSATION_IDS:"
|
||||
//conversationIDsHashKey = "CONVERSATION_IDS_HASH:"
|
||||
//conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
|
||||
//recvMsgOptKey = "RECV_MSG_OPT:"
|
||||
//superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
|
||||
//superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
|
||||
//conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:".
|
||||
// ConversationKey = "CONVERSATION:"
|
||||
// conversationIDsKey = "CONVERSATION_IDS:"
|
||||
// conversationIDsHashKey = "CONVERSATION_IDS_HASH:"
|
||||
// conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
|
||||
// recvMsgOptKey = "RECV_MSG_OPT:"
|
||||
// superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
|
||||
// superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
|
||||
// conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:".
|
||||
|
||||
conversationExpireTime = time.Second * 60 * 60 * 12
|
||||
)
|
||||
@@ -66,13 +67,13 @@ type ConversationCache interface {
|
||||
GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error)
|
||||
DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache
|
||||
// get one super group recv msg but do not notification userID list
|
||||
//GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error)
|
||||
// GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error)
|
||||
DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache
|
||||
// get one super group recv msg but do not notification userID list hash
|
||||
//GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error)
|
||||
// GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error)
|
||||
DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache
|
||||
|
||||
//GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
|
||||
// GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
|
||||
DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache
|
||||
|
||||
GetConversationsByConversationID(ctx context.Context,
|
||||
@@ -82,10 +83,10 @@ type ConversationCache interface {
|
||||
DelConversationNotReceiveMessageUserIDs(conversationIDs ...string) ConversationCache
|
||||
}
|
||||
|
||||
func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache {
|
||||
func NewConversationRedis(rdb redis.UniversalClient, localCache *config.LocalCache, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache {
|
||||
rcClient := rockscache.NewClient(rdb, opts)
|
||||
mc := NewMetaCacheRedis(rcClient)
|
||||
c := config.Config.LocalCache.Conversation
|
||||
c := localCache.Conversation
|
||||
log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable())
|
||||
mc.SetTopic(c.Topic)
|
||||
mc.SetRawRedisClient(rdb)
|
||||
@@ -104,11 +105,11 @@ type ConversationRedisCache struct {
|
||||
expireTime time.Duration
|
||||
}
|
||||
|
||||
//func NewNewConversationRedis(
|
||||
// func NewNewConversationRedis(
|
||||
// rdb redis.UniversalClient,
|
||||
// conversationDB *relation.ConversationGorm,
|
||||
// options rockscache.Options,
|
||||
//) ConversationCache {
|
||||
// ) ConversationCache {
|
||||
// rcClient := rockscache.NewClient(rdb, options)
|
||||
//
|
||||
// return &ConversationRedisCache{
|
||||
@@ -188,9 +189,9 @@ func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context,
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
utils.Sort(conversationIDs, true)
|
||||
datautil.Sort(conversationIDs, true)
|
||||
bi := big.NewInt(0)
|
||||
bi.SetString(utils.Md5(strings.Join(conversationIDs, ";"))[0:8], 16)
|
||||
bi.SetString(encrypt.Md5(strings.Join(conversationIDs, ";"))[0:8], 16)
|
||||
return bi.Uint64(), nil
|
||||
},
|
||||
)
|
||||
@@ -232,15 +233,15 @@ func (c *ConversationRedisCache) DelConversations(ownerUserID string, conversati
|
||||
// }
|
||||
// }
|
||||
|
||||
// return 0, errors.New("not found key:" + key + " in keys")
|
||||
// return 0, errs.New("not found key:" + key + " in keys")
|
||||
// }
|
||||
|
||||
func (c *ConversationRedisCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error) {
|
||||
//var keys []string
|
||||
//for _, conversarionID := range conversationIDs {
|
||||
// var keys []string
|
||||
// for _, conversarionID := range conversationIDs {
|
||||
// keys = append(keys, c.getConversationKey(ownerUserID, conversarionID))
|
||||
//}
|
||||
//return batchGetCache(
|
||||
// return batchGetCache(
|
||||
// ctx,
|
||||
// c.rcClient,
|
||||
// keys,
|
||||
@@ -262,11 +263,11 @@ func (c *ConversationRedisCache) GetUserAllConversations(ctx context.Context, ow
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//var keys []string
|
||||
//for _, conversarionID := range conversationIDs {
|
||||
// var keys []string
|
||||
// for _, conversarionID := range conversationIDs {
|
||||
// keys = append(keys, c.getConversationKey(ownerUserID, conversarionID))
|
||||
//}
|
||||
//return batchGetCache(
|
||||
// return batchGetCache(
|
||||
// ctx,
|
||||
// c.rcClient,
|
||||
// keys,
|
||||
@@ -285,7 +286,7 @@ 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 c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
|
||||
// })
|
||||
@@ -316,7 +317,7 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID st
|
||||
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) {
|
||||
// userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
|
||||
// if err != nil {
|
||||
@@ -337,30 +338,6 @@ func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupI
|
||||
return cache
|
||||
}
|
||||
|
||||
/* func (c *ConversationRedisCache) getUserAllHasReadSeqsIndex(conversationID string, conversationIDs []string) (int, error) {
|
||||
for _i, _conversationID := range conversationIDs {
|
||||
if _conversationID == conversationID {
|
||||
return _i, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("not found key:" + conversationID + " in keys")
|
||||
} */
|
||||
|
||||
/* func (c *ConversationRedisCache) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) {
|
||||
conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var keys []string
|
||||
for _, conversarionID := range conversationIDs {
|
||||
keys = append(keys, c.getConversationHasReadSeqKey(ownerUserID, conversarionID))
|
||||
}
|
||||
return batchGetCacheMap(ctx, c.rcClient, keys, conversationIDs, c.expireTime, c.getUserAllHasReadSeqsIndex, func(ctx context.Context) (map[string]int64, error) {
|
||||
return c.conversationDB.GetUserAllHasReadSeqs(ctx, ownerUserID)
|
||||
})
|
||||
} */
|
||||
|
||||
func (c *ConversationRedisCache) DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache {
|
||||
cache := c.NewCache()
|
||||
for _, conversationID := range conversationIDs {
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
Vendored
+8
-8
@@ -18,20 +18,20 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
friendExpireTime = time.Second * 60 * 60 * 12
|
||||
//friendIDsKey = "FRIEND_IDS:"
|
||||
//TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
|
||||
//friendKey = "FRIEND_INFO:".
|
||||
// FriendIDsKey = "FRIEND_IDS:"
|
||||
// TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
|
||||
// friendKey = "FRIEND_INFO:".
|
||||
)
|
||||
|
||||
// FriendCache is an interface for caching friend-related data.
|
||||
@@ -58,11 +58,11 @@ type FriendCacheRedis struct {
|
||||
}
|
||||
|
||||
// NewFriendCacheRedis creates a new instance of FriendCacheRedis.
|
||||
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface,
|
||||
func NewFriendCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, friendDB relationtb.FriendModelInterface,
|
||||
options rockscache.Options) FriendCache {
|
||||
rcClient := rockscache.NewClient(rdb, options)
|
||||
mc := NewMetaCacheRedis(rcClient)
|
||||
f := config.Config.LocalCache.Friend
|
||||
f := localCache.Friend
|
||||
log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable())
|
||||
mc.SetTopic(f.Topic)
|
||||
mc.SetRawRedisClient(rdb)
|
||||
@@ -129,7 +129,7 @@ func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if utils.IsContain(ownerUserID, friendFriendID) {
|
||||
if datautil.Contain(ownerUserID, friendFriendID...) {
|
||||
twoWayFriendIDs = append(twoWayFriendIDs, ownerUserID)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+12
-18
@@ -19,26 +19,19 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
groupExpireTime = time.Second * 60 * 60 * 12
|
||||
//groupInfoKey = "GROUP_INFO:"
|
||||
//groupMemberIDsKey = "GROUP_MEMBER_IDS:"
|
||||
//groupMembersHashKey = "GROUP_MEMBERS_HASH2:"
|
||||
//groupMemberInfoKey = "GROUP_MEMBER_INFO:"
|
||||
//joinedGroupsKey = "JOIN_GROUPS_KEY:"
|
||||
//groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
||||
//groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:".
|
||||
)
|
||||
|
||||
type GroupHash interface {
|
||||
@@ -94,6 +87,7 @@ type GroupCacheRedis struct {
|
||||
|
||||
func NewGroupCacheRedis(
|
||||
rdb redis.UniversalClient,
|
||||
localCache *config.LocalCache,
|
||||
groupDB relationtb.GroupModelInterface,
|
||||
groupMemberDB relationtb.GroupMemberModelInterface,
|
||||
groupRequestDB relationtb.GroupRequestModelInterface,
|
||||
@@ -102,7 +96,7 @@ func NewGroupCacheRedis(
|
||||
) GroupCache {
|
||||
rcClient := rockscache.NewClient(rdb, opts)
|
||||
mc := NewMetaCacheRedis(rcClient)
|
||||
g := config.Config.LocalCache.Group
|
||||
g := localCache.Group
|
||||
mc.SetTopic(g.Topic)
|
||||
log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable())
|
||||
mc.SetRawRedisClient(rdb)
|
||||
@@ -227,7 +221,7 @@ func (g *GroupCacheRedis) DelGroupAllRoleLevel(groupID string) GroupCache {
|
||||
|
||||
func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) {
|
||||
if g.groupHash == nil {
|
||||
return 0, errs.ErrInternalServer.Wrap("group hash is nil")
|
||||
return 0, errs.ErrInternalServer.WrapMsg("group hash is nil")
|
||||
}
|
||||
return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) {
|
||||
return g.groupHash.GetGroupHash(ctx, groupID)
|
||||
@@ -236,7 +230,7 @@ func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID strin
|
||||
|
||||
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")
|
||||
return nil, errs.ErrInternalServer.WrapMsg("group hash is nil")
|
||||
}
|
||||
res := make(map[string]*relationtb.GroupSimpleUserID)
|
||||
for _, groupID := range groupIDs {
|
||||
@@ -244,7 +238,7 @@ func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.ZInfo(ctx, "GetGroupMemberHashMap", "groupID", groupID, "hash", hash)
|
||||
log.ZDebug(ctx, "GetGroupMemberHashMap", "groupID", groupID, "hash", hash)
|
||||
num, err := g.GetGroupMemberNum(ctx, groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -330,11 +324,11 @@ func (g *GroupCacheRedis) GetGroupMembersPage(
|
||||
return 0, nil, err
|
||||
}
|
||||
if userIDs != nil {
|
||||
userIDs = utils.BothExist(userIDs, groupMemberIDs)
|
||||
userIDs = datautil.BothExist(userIDs, groupMemberIDs)
|
||||
} else {
|
||||
userIDs = groupMemberIDs
|
||||
}
|
||||
groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, utils.Paginate(userIDs, int(showNumber), int(showNumber)))
|
||||
groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, datautil.Paginate(userIDs, int(showNumber), int(showNumber)))
|
||||
|
||||
return uint32(len(userIDs)), groupMembers, err
|
||||
}
|
||||
@@ -390,7 +384,7 @@ func (g *GroupCacheRedis) GetGroupOwner(ctx context.Context, groupID string) (*r
|
||||
return nil, err
|
||||
}
|
||||
if len(members) == 0 {
|
||||
return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("group %s owner not found", groupID))
|
||||
return nil, errs.ErrRecordNotFound.WrapMsg(fmt.Sprintf("group %s owner not found", groupID))
|
||||
}
|
||||
return members[0], nil
|
||||
}
|
||||
|
||||
Vendored
-107
@@ -1,107 +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 cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mw/specialerror"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var (
|
||||
// singleton pattern.
|
||||
redisClient redis.UniversalClient
|
||||
)
|
||||
|
||||
const (
|
||||
maxRetry = 10 // number of retries
|
||||
)
|
||||
|
||||
// NewRedis Initialize redis connection.
|
||||
func NewRedis(config *config.GlobalConfig) (redis.UniversalClient, error) {
|
||||
if redisClient != nil {
|
||||
return redisClient, nil
|
||||
}
|
||||
|
||||
// Read configuration from environment variables
|
||||
overrideConfigFromEnv(config)
|
||||
|
||||
if len(config.Redis.Address) == 0 {
|
||||
return nil, errs.Wrap(errors.New("redis address is empty"))
|
||||
}
|
||||
specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound)
|
||||
var rdb redis.UniversalClient
|
||||
if len(config.Redis.Address) > 1 || config.Redis.ClusterMode {
|
||||
rdb = redis.NewClusterClient(&redis.ClusterOptions{
|
||||
Addrs: config.Redis.Address,
|
||||
Username: config.Redis.Username,
|
||||
Password: config.Redis.Password, // no password set
|
||||
PoolSize: 50,
|
||||
MaxRetries: maxRetry,
|
||||
})
|
||||
} else {
|
||||
rdb = redis.NewClient(&redis.Options{
|
||||
Addr: config.Redis.Address[0],
|
||||
Username: config.Redis.Username,
|
||||
Password: config.Redis.Password,
|
||||
DB: 0, // use default DB
|
||||
PoolSize: 100, // connection pool size
|
||||
MaxRetries: maxRetry,
|
||||
})
|
||||
}
|
||||
|
||||
var err error
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
err = rdb.Ping(ctx).Err()
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("address:%s, username:%s, password:%s, clusterMode:%t, enablePipeline:%t", config.Redis.Address, config.Redis.Username,
|
||||
config.Redis.Password, config.Redis.ClusterMode, config.Redis.EnablePipeline)
|
||||
return nil, errs.Wrap(err, errMsg)
|
||||
}
|
||||
redisClient = rdb
|
||||
return rdb, err
|
||||
}
|
||||
|
||||
// overrideConfigFromEnv overrides configuration fields with environment variables if present.
|
||||
func overrideConfigFromEnv(config *config.GlobalConfig) {
|
||||
if envAddr := os.Getenv("REDIS_ADDRESS"); envAddr != "" {
|
||||
if envPort := os.Getenv("REDIS_PORT"); envPort != "" {
|
||||
addresses := strings.Split(envAddr, ",")
|
||||
for i, addr := range addresses {
|
||||
addresses[i] = addr + ":" + envPort
|
||||
}
|
||||
config.Redis.Address = addresses
|
||||
} else {
|
||||
config.Redis.Address = strings.Split(envAddr, ",")
|
||||
}
|
||||
}
|
||||
|
||||
if envUser := os.Getenv("REDIS_USERNAME"); envUser != "" {
|
||||
config.Redis.Username = envUser
|
||||
}
|
||||
|
||||
if envPass := os.Getenv("REDIS_PASSWORD"); envPass != "" {
|
||||
config.Redis.Password = envPass
|
||||
}
|
||||
}
|
||||
Vendored
+12
-13
@@ -17,15 +17,14 @@ package cache
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/mw/specialerror"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mw/specialerror"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
@@ -35,7 +34,7 @@ const (
|
||||
retryInterval = time.Millisecond * 100
|
||||
)
|
||||
|
||||
var errIndex = errors.New("err index")
|
||||
var errIndex = errs.New("err index")
|
||||
|
||||
type metaCache interface {
|
||||
ExecDel(ctx context.Context, distinct ...bool) error
|
||||
@@ -74,7 +73,7 @@ func (m *metaCacheRedis) Copy() metaCache {
|
||||
keys: keys,
|
||||
maxRetryTimes: m.maxRetryTimes,
|
||||
retryInterval: m.retryInterval,
|
||||
redisClient: redisClient,
|
||||
redisClient: m.redisClient,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +87,7 @@ func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) {
|
||||
|
||||
func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
||||
if len(distinct) > 0 && distinct[0] {
|
||||
m.keys = utils.Distinct(m.keys)
|
||||
m.keys = datautil.Distinct(m.keys)
|
||||
}
|
||||
if len(m.keys) > 0 {
|
||||
log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys)
|
||||
@@ -150,7 +149,7 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin
|
||||
}
|
||||
bs, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err, "marshal failed")
|
||||
return "", errs.WrapMsg(err, "marshal failed")
|
||||
}
|
||||
write = true
|
||||
|
||||
@@ -163,12 +162,12 @@ func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key strin
|
||||
return t, nil
|
||||
}
|
||||
if v == "" {
|
||||
return t, errs.ErrRecordNotFound.Wrap("cache is not found")
|
||||
return t, errs.ErrRecordNotFound.WrapMsg("cache is not found")
|
||||
}
|
||||
err = json.Unmarshal([]byte(v), &t)
|
||||
if err != nil {
|
||||
errInfo := fmt.Sprintf("cache json.Unmarshal failed, key:%s, value:%s, expire:%s", key, v, expire)
|
||||
return t, errs.Wrap(err, errInfo)
|
||||
return t, errs.WrapMsg(err, errInfo)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
@@ -240,14 +239,14 @@ func batchGetCache2[T any, K comparable](
|
||||
return res, nil
|
||||
}
|
||||
|
||||
//func batchGetCacheMap[T any](
|
||||
// func batchGetCacheMap[T any](
|
||||
// ctx context.Context,
|
||||
// rcClient *rockscache.Client,
|
||||
// keys, originKeys []string,
|
||||
// expire time.Duration,
|
||||
// keyIndexFn func(s string, keys []string) (int, error),
|
||||
// fn func(ctx context.Context) (map[string]T, error),
|
||||
//) (map[string]T, error) {
|
||||
// ) (map[string]T, error) {
|
||||
// batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) {
|
||||
// tArrays, err := fn(ctx)
|
||||
// if err != nil {
|
||||
|
||||
Vendored
+377
-644
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -20,7 +20,7 @@ import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
Vendored
+17
-15
@@ -16,12 +16,14 @@ package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/tools/s3/cont"
|
||||
"github.com/openimsdk/tools/s3/minio"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/s3"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
@@ -83,7 +85,7 @@ type S3Cache interface {
|
||||
DelS3Key(engine string, keys ...string) S3Cache
|
||||
}
|
||||
|
||||
func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) S3Cache {
|
||||
func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) cont.S3Cache {
|
||||
rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions())
|
||||
return &s3CacheRedis{
|
||||
rcClient: rcClient,
|
||||
@@ -100,7 +102,7 @@ type s3CacheRedis struct {
|
||||
expireTime time.Duration
|
||||
}
|
||||
|
||||
func (g *s3CacheRedis) NewCache() S3Cache {
|
||||
func (g *s3CacheRedis) newCache() *s3CacheRedis {
|
||||
return &s3CacheRedis{
|
||||
rcClient: g.rcClient,
|
||||
expireTime: g.expireTime,
|
||||
@@ -109,14 +111,14 @@ func (g *s3CacheRedis) NewCache() S3Cache {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *s3CacheRedis) DelS3Key(engine string, keys ...string) S3Cache {
|
||||
s3cache := g.NewCache()
|
||||
func (g *s3CacheRedis) DelS3Key(ctx context.Context, engine string, keys ...string) error {
|
||||
s3cache := g.newCache()
|
||||
ks := make([]string, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
ks = append(ks, g.getS3Key(engine, key))
|
||||
}
|
||||
s3cache.AddKeys(ks...)
|
||||
return s3cache
|
||||
return s3cache.ExecDel(ctx)
|
||||
}
|
||||
|
||||
func (g *s3CacheRedis) getS3Key(engine string, name string) string {
|
||||
@@ -137,7 +139,7 @@ type MinioCache interface {
|
||||
DelImageThumbnailKey(key string, format string, width int, height int) MinioCache
|
||||
}
|
||||
|
||||
func NewMinioCache(rdb redis.UniversalClient) MinioCache {
|
||||
func NewMinioCache(rdb redis.UniversalClient) minio.Cache {
|
||||
rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions())
|
||||
return &minioCacheRedis{
|
||||
rcClient: rcClient,
|
||||
@@ -152,7 +154,7 @@ type minioCacheRedis struct {
|
||||
expireTime time.Duration
|
||||
}
|
||||
|
||||
func (g *minioCacheRedis) NewCache() MinioCache {
|
||||
func (g *minioCacheRedis) newCache() *minioCacheRedis {
|
||||
return &minioCacheRedis{
|
||||
rcClient: g.rcClient,
|
||||
expireTime: g.expireTime,
|
||||
@@ -160,20 +162,20 @@ func (g *minioCacheRedis) NewCache() MinioCache {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *minioCacheRedis) DelObjectImageInfoKey(keys ...string) MinioCache {
|
||||
s3cache := g.NewCache()
|
||||
func (g *minioCacheRedis) DelObjectImageInfoKey(ctx context.Context, keys ...string) error {
|
||||
s3cache := g.newCache()
|
||||
ks := make([]string, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
ks = append(ks, g.getObjectImageInfoKey(key))
|
||||
}
|
||||
s3cache.AddKeys(ks...)
|
||||
return s3cache
|
||||
return s3cache.ExecDel(ctx)
|
||||
}
|
||||
|
||||
func (g *minioCacheRedis) DelImageThumbnailKey(key string, format string, width int, height int) MinioCache {
|
||||
s3cache := g.NewCache()
|
||||
func (g *minioCacheRedis) DelImageThumbnailKey(ctx context.Context, key string, format string, width int, height int) error {
|
||||
s3cache := g.newCache()
|
||||
s3cache.AddKeys(g.getMinioImageThumbnailKey(key, format, width, height))
|
||||
return s3cache
|
||||
return s3cache.ExecDel(ctx)
|
||||
}
|
||||
|
||||
func (g *minioCacheRedis) getObjectImageInfoKey(key string) string {
|
||||
@@ -184,7 +186,7 @@ func (g *minioCacheRedis) getMinioImageThumbnailKey(key string, format string, w
|
||||
return "MINIO:THUMBNAIL:" + format + ":w" + strconv.Itoa(width) + ":h" + strconv.Itoa(height) + ":" + key
|
||||
}
|
||||
|
||||
func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*MinioImageInfo, error)) (*MinioImageInfo, error) {
|
||||
func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*minio.ImageInfo, error)) (*minio.ImageInfo, error) {
|
||||
info, err := getCache(ctx, g.rcClient, g.getObjectImageInfoKey(key), g.expireTime, fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type SeqCache interface {
|
||||
SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error
|
||||
GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error)
|
||||
GetMaxSeq(ctx context.Context, conversationID string) (int64, error)
|
||||
SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error
|
||||
SetMinSeqs(ctx context.Context, seqs map[string]int64) error
|
||||
GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error)
|
||||
GetMinSeq(ctx context.Context, conversationID string) (int64, error)
|
||||
GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error)
|
||||
GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error)
|
||||
SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error
|
||||
// seqs map: key userID value minSeq
|
||||
SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error)
|
||||
// seqs map: key conversationID value minSeq
|
||||
SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error
|
||||
// has read seq
|
||||
SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error
|
||||
// k: user, v: seq
|
||||
SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error
|
||||
// k: conversation, v :seq
|
||||
UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error
|
||||
GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error)
|
||||
GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error)
|
||||
}
|
||||
|
||||
func NewSeqCache(rdb redis.UniversalClient) SeqCache {
|
||||
return &seqCache{rdb: rdb}
|
||||
}
|
||||
|
||||
type seqCache struct {
|
||||
rdb redis.UniversalClient
|
||||
}
|
||||
|
||||
func (c *seqCache) getMaxSeqKey(conversationID string) string {
|
||||
return maxSeq + conversationID
|
||||
}
|
||||
|
||||
func (c *seqCache) getMinSeqKey(conversationID string) string {
|
||||
return minSeq + conversationID
|
||||
}
|
||||
|
||||
func (c *seqCache) getHasReadSeqKey(conversationID string, userID string) string {
|
||||
return hasReadSeq + userID + ":" + conversationID
|
||||
}
|
||||
|
||||
func (c *seqCache) getConversationUserMinSeqKey(conversationID, userID string) string {
|
||||
return conversationUserMinSeq + conversationID + "u:" + userID
|
||||
}
|
||||
|
||||
func (c *seqCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
|
||||
}
|
||||
|
||||
func (c *seqCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) {
|
||||
val, err := c.rdb.Get(ctx, getkey(conversationID)).Int64()
|
||||
if err != nil {
|
||||
return 0, errs.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *seqCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) {
|
||||
m = make(map[string]int64, len(items))
|
||||
for i, v := range items {
|
||||
res, err := c.rdb.Get(ctx, getkey(v)).Result()
|
||||
if err != nil && err != redis.Nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
val := stringutil.StringToInt64(res)
|
||||
if val != 0 {
|
||||
m[items[i]] = val
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *seqCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error {
|
||||
return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) {
|
||||
return c.getSeqs(ctx, conversationIDs, c.getMaxSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) {
|
||||
return c.getSeq(ctx, conversationID, c.getMaxSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
|
||||
return c.setSeq(ctx, conversationID, minSeq, c.getMinSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) setSeqs(ctx context.Context, seqs map[string]int64, getkey func(key string) string) error {
|
||||
for conversationID, seq := range seqs {
|
||||
if err := c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err(); err != nil {
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *seqCache) SetMinSeqs(ctx context.Context, seqs map[string]int64) error {
|
||||
return c.setSeqs(ctx, seqs, c.getMinSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
|
||||
return c.getSeqs(ctx, conversationIDs, c.getMinSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) GetMinSeq(ctx context.Context, conversationID string) (int64, error) {
|
||||
return c.getSeq(ctx, conversationID, c.getMinSeqKey)
|
||||
}
|
||||
|
||||
func (c *seqCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
|
||||
val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()
|
||||
if err != nil {
|
||||
return 0, errs.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *seqCache) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (m map[string]int64, err error) {
|
||||
return c.getSeqs(ctx, userIDs, func(userID string) string {
|
||||
return c.getConversationUserMinSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err())
|
||||
}
|
||||
|
||||
func (c *seqCache) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) {
|
||||
return c.setSeqs(ctx, seqs, func(userID string) string {
|
||||
return c.getConversationUserMinSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error) {
|
||||
return c.setSeqs(ctx, seqs, func(conversationID string) string {
|
||||
return c.getConversationUserMinSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err())
|
||||
}
|
||||
|
||||
func (c *seqCache) SetHasReadSeqs(ctx context.Context, conversationID string, hasReadSeqs map[string]int64) error {
|
||||
return c.setSeqs(ctx, hasReadSeqs, func(userID string) string {
|
||||
return c.getHasReadSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error {
|
||||
return c.setSeqs(ctx, hasReadSeqs, func(conversationID string) string {
|
||||
return c.getHasReadSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) {
|
||||
return c.getSeqs(ctx, conversationIDs, func(conversationID string) string {
|
||||
return c.getHasReadSeqKey(conversationID, userID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *seqCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) {
|
||||
val, err := c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ThirdCache interface {
|
||||
SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error)
|
||||
GetFcmToken(ctx context.Context, account string, platformID int) (string, error)
|
||||
DelFcmToken(ctx context.Context, account string, platformID int) error
|
||||
IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error)
|
||||
SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error
|
||||
GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error)
|
||||
SetGetuiToken(ctx context.Context, token string, expireTime int64) error
|
||||
GetGetuiToken(ctx context.Context) (string, error)
|
||||
SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error
|
||||
GetGetuiTaskID(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
func NewThirdCache(rdb redis.UniversalClient) ThirdCache {
|
||||
return &thirdCache{rdb: rdb}
|
||||
}
|
||||
|
||||
type thirdCache struct {
|
||||
rdb redis.UniversalClient
|
||||
}
|
||||
|
||||
func (c *thirdCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) {
|
||||
return errs.Wrap(c.rdb.Set(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID), fcmToken, time.Duration(expireTime)*time.Second).Err())
|
||||
}
|
||||
|
||||
func (c *thirdCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) {
|
||||
val, err := c.rdb.Get(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Result()
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *thirdCache) DelFcmToken(ctx context.Context, account string, platformID int) error {
|
||||
return errs.Wrap(c.rdb.Del(ctx, FCM_TOKEN+account+":"+strconv.Itoa(platformID)).Err())
|
||||
}
|
||||
|
||||
func (c *thirdCache) IncrUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) {
|
||||
seq, err := c.rdb.Incr(ctx, userBadgeUnreadCountSum+userID).Result()
|
||||
|
||||
return int(seq), errs.Wrap(err)
|
||||
}
|
||||
|
||||
func (c *thirdCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, userBadgeUnreadCountSum+userID, value, 0).Err())
|
||||
}
|
||||
|
||||
func (c *thirdCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) {
|
||||
val, err := c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int()
|
||||
return val, errs.Wrap(err)
|
||||
}
|
||||
|
||||
func (c *thirdCache) SetGetuiToken(ctx context.Context, token string, expireTime int64) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, getuiToken, token, time.Duration(expireTime)*time.Second).Err())
|
||||
}
|
||||
|
||||
func (c *thirdCache) GetGetuiToken(ctx context.Context) (string, error) {
|
||||
val, err := c.rdb.Get(ctx, getuiToken).Result()
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *thirdCache) SetGetuiTaskID(ctx context.Context, taskID string, expireTime int64) error {
|
||||
return errs.Wrap(c.rdb.Set(ctx, getuiTaskID, taskID, time.Duration(expireTime)*time.Second).Err())
|
||||
}
|
||||
|
||||
func (c *thirdCache) GetGetuiTaskID(ctx context.Context) (string, error) {
|
||||
val, err := c.rdb.Get(ctx, getuiTaskID).Result()
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
func NewTokenCacheModel(rdb redis.UniversalClient) TokenModel {
|
||||
return &tokenCache{
|
||||
rdb: rdb,
|
||||
}
|
||||
}
|
||||
|
||||
type TokenModel interface {
|
||||
AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error
|
||||
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
|
||||
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
||||
DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error
|
||||
}
|
||||
|
||||
type tokenCache struct {
|
||||
rdb redis.UniversalClient
|
||||
}
|
||||
|
||||
func (c *tokenCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error {
|
||||
return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), token, flag).Err())
|
||||
}
|
||||
|
||||
func (c *tokenCache) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
|
||||
m, err := c.rdb.HGetAll(ctx, cachekey.GetTokenKey(userID, platformID)).Result()
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
mm := make(map[string]int)
|
||||
for k, v := range m {
|
||||
mm[k] = stringutil.StringToInt(v)
|
||||
}
|
||||
|
||||
return mm, nil
|
||||
}
|
||||
|
||||
func (c *tokenCache) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error {
|
||||
mm := make(map[string]any)
|
||||
for k, v := range m {
|
||||
mm[k] = v
|
||||
}
|
||||
return errs.Wrap(c.rdb.HSet(ctx, cachekey.GetTokenKey(userID, platformID), mm).Err())
|
||||
}
|
||||
|
||||
func (c *tokenCache) DeleteTokenByUidPid(ctx context.Context, userID string, platformID int, fields []string) error {
|
||||
return errs.Wrap(c.rdb.HDel(ctx, cachekey.GetTokenKey(userID, platformID), fields...).Err())
|
||||
}
|
||||
Vendored
+9
-16
@@ -22,25 +22,22 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/protocol/user"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/user"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
userExpireTime = time.Second * 60 * 60 * 12
|
||||
//userInfoKey = "USER_INFO:".
|
||||
userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
|
||||
userExpireTime = time.Second * 60 * 60 * 12
|
||||
olineStatusKey = "ONLINE_STATUS:"
|
||||
userOlineStatusExpireTime = time.Second * 60 * 60 * 24
|
||||
statusMod = 501
|
||||
platformID = "_PlatformIDSuffix"
|
||||
)
|
||||
|
||||
type UserCache interface {
|
||||
@@ -58,20 +55,16 @@ type UserCache interface {
|
||||
type UserCacheRedis struct {
|
||||
metaCache
|
||||
rdb redis.UniversalClient
|
||||
//userDB relationtb.UserModelInterface
|
||||
// userDB relationtb.UserModelInterface
|
||||
userDB relationtb.UserModelInterface
|
||||
expireTime time.Duration
|
||||
rcClient *rockscache.Client
|
||||
}
|
||||
|
||||
func NewUserCacheRedis(
|
||||
rdb redis.UniversalClient,
|
||||
userDB relationtb.UserModelInterface,
|
||||
options rockscache.Options,
|
||||
) UserCache {
|
||||
func NewUserCacheRedis(rdb redis.UniversalClient, localCache *config.LocalCache, userDB relationtb.UserModelInterface, options rockscache.Options) UserCache {
|
||||
rcClient := rockscache.NewClient(rdb, options)
|
||||
mc := NewMetaCacheRedis(rcClient)
|
||||
u := config.Config.LocalCache.User
|
||||
u := localCache.User
|
||||
log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable())
|
||||
mc.SetTopic(u.Topic)
|
||||
mc.SetRawRedisClient(rdb)
|
||||
@@ -294,7 +287,7 @@ func (u *UserCacheRedis) refreshStatusOnline(ctx context.Context, userID string,
|
||||
onlineStatus.UserID = userID
|
||||
newjsonData, err := json.Marshal(&onlineStatus)
|
||||
if err != nil {
|
||||
return errs.Wrap(err, "json.Marshal failed")
|
||||
return errs.WrapMsg(err, "json.Marshal failed")
|
||||
}
|
||||
_, err = u.rdb.HSet(ctx, key, userID, string(newjsonData)).Result()
|
||||
if err != nil {
|
||||
|
||||
@@ -17,13 +17,12 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/tokenverify"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/tokenverify"
|
||||
)
|
||||
|
||||
type AuthDatabase interface {
|
||||
@@ -31,17 +30,18 @@ type AuthDatabase interface {
|
||||
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
|
||||
// Create token
|
||||
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
|
||||
|
||||
SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error
|
||||
}
|
||||
|
||||
type authDatabase struct {
|
||||
cache cache.MsgModel
|
||||
cache cache.TokenModel
|
||||
accessSecret string
|
||||
accessExpire int64
|
||||
config *config.GlobalConfig
|
||||
}
|
||||
|
||||
func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64, config *config.GlobalConfig) AuthDatabase {
|
||||
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire, config: config}
|
||||
func NewAuthDatabase(cache cache.TokenModel, accessSecret string, accessExpire int64) AuthDatabase {
|
||||
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire}
|
||||
}
|
||||
|
||||
// If the result is empty.
|
||||
@@ -49,6 +49,10 @@ func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string,
|
||||
return a.cache.GetTokensWithoutError(ctx, userID, platformID)
|
||||
}
|
||||
|
||||
func (a *authDatabase) SetTokenMapByUidPid(ctx context.Context, userID string, platformID int, m map[string]int) error {
|
||||
return a.cache.SetTokenMapByUidPid(ctx, userID, platformID, m)
|
||||
}
|
||||
|
||||
// Create Token.
|
||||
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
|
||||
tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID)
|
||||
@@ -57,7 +61,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI
|
||||
}
|
||||
var deleteTokenKey []string
|
||||
for k, v := range tokens {
|
||||
_, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.config.Secret))
|
||||
_, err = tokenverify.GetClaimFromToken(k, authverify.Secret(a.accessSecret))
|
||||
if err != nil || v != constant.NormalToken {
|
||||
deleteTokenKey = append(deleteTokenKey, k)
|
||||
}
|
||||
@@ -73,7 +77,7 @@ func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformI
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString([]byte(a.accessSecret))
|
||||
if err != nil {
|
||||
return "", errs.Wrap(err, "token.SignedString")
|
||||
return "", errs.WrapMsg(err, "token.SignedString")
|
||||
}
|
||||
return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken)
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
type BlackDatabase interface {
|
||||
@@ -86,7 +86,7 @@ func (b *blackDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (i
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "blackIDs", "user1BlackIDs", userID1BlackIDs, "user2BlackIDs", userID2BlackIDs)
|
||||
return utils.IsContain(userID2, userID1BlackIDs), utils.IsContain(userID1, userID2BlackIDs), nil
|
||||
return datautil.Contain(userID2, userID1BlackIDs...), datautil.Contain(userID1, userID2BlackIDs...), nil
|
||||
}
|
||||
|
||||
// FindBlackIDs Get Blacklist List.
|
||||
|
||||
@@ -18,14 +18,15 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/OpenIMSDK/tools/tx"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/db/tx"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
)
|
||||
|
||||
type ConversationDatabase interface {
|
||||
@@ -62,11 +63,11 @@ type ConversationDatabase interface {
|
||||
GetConversationIDsNeedDestruct(ctx context.Context) ([]*relationtb.ConversationModel, error)
|
||||
// GetConversationNotReceiveMessageUserIDs gets user IDs for users in a conversation who have not received messages.
|
||||
GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error)
|
||||
//GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
|
||||
//FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
|
||||
// GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
|
||||
// FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
|
||||
}
|
||||
|
||||
func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase {
|
||||
func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase {
|
||||
return &conversationDatabase{
|
||||
conversationDB: conversation,
|
||||
cache: cache,
|
||||
@@ -77,7 +78,7 @@ func NewConversationDatabase(conversation relationtb.ConversationModelInterface,
|
||||
type conversationDatabase struct {
|
||||
conversationDB relationtb.ConversationModelInterface
|
||||
cache cache.ConversationCache
|
||||
tx tx.CtxTx
|
||||
tx tx.Tx
|
||||
}
|
||||
|
||||
func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) {
|
||||
@@ -105,13 +106,13 @@ func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context,
|
||||
cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID)
|
||||
}
|
||||
}
|
||||
NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs)
|
||||
NotUserIDs := stringutil.DifferenceString(haveUserIDs, userIDs)
|
||||
log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
|
||||
var conversations []*relationtb.ConversationModel
|
||||
now := time.Now()
|
||||
for _, v := range NotUserIDs {
|
||||
temp := new(relationtb.ConversationModel)
|
||||
if err = utils.CopyStructFields(temp, conversation); err != nil {
|
||||
if err = datautil.CopyStructFields(temp, conversation); err != nil {
|
||||
return err
|
||||
}
|
||||
temp.OwnerUserID = v
|
||||
@@ -205,7 +206,7 @@ func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, owner
|
||||
func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error {
|
||||
return c.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
cache := c.cache.NewCache()
|
||||
groupIDs := utils.Distinct(utils.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) {
|
||||
groupIDs := datautil.Distinct(datautil.Filter(conversations, func(e *relationtb.ConversationModel) (string, bool) {
|
||||
return e.GroupID, e.GroupID != ""
|
||||
}))
|
||||
for _, groupID := range groupIDs {
|
||||
@@ -235,7 +236,7 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs
|
||||
|
||||
var notExistConversations []*relationtb.ConversationModel
|
||||
for _, conversation := range conversations {
|
||||
if !utils.IsContain(conversation.ConversationID, existConversationIDs) {
|
||||
if !datautil.Contain(conversation.ConversationID, existConversationIDs...) {
|
||||
notExistConversations = append(notExistConversations, conversation)
|
||||
}
|
||||
}
|
||||
@@ -246,28 +247,28 @@ func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUs
|
||||
}
|
||||
cache = cache.DelConversationIDs(ownerUserID).
|
||||
DelUserConversationIDsHash(ownerUserID).
|
||||
DelConversationNotReceiveMessageUserIDs(utils.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...)
|
||||
DelConversationNotReceiveMessageUserIDs(datautil.Slice(notExistConversations, func(e *relationtb.ConversationModel) string { return e.ConversationID })...)
|
||||
}
|
||||
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)
|
||||
//}
|
||||
|
||||
func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error {
|
||||
return c.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
cache := c.cache.NewCache()
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID)
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||
existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notExistUserIDs := utils.DifferenceString(userIDs, existConversationUserIDs)
|
||||
notExistUserIDs := stringutil.DifferenceString(userIDs, existConversationUserIDs)
|
||||
var conversations []*relationtb.ConversationModel
|
||||
for _, v := range notExistUserIDs {
|
||||
conversation := relationtb.ConversationModel{ConversationType: constant.SuperGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID}
|
||||
conversation := relationtb.ConversationModel{ConversationType: constant.ReadGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID}
|
||||
conversations = append(conversations, &conversation)
|
||||
cache = cache.DelConversations(v, conversationID).DelConversationNotReceiveMessageUserIDs(conversationID)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
|
||||
@@ -19,15 +19,15 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/mcontext"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/OpenIMSDK/tools/tx"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/db/tx"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
type FriendDatabase interface {
|
||||
@@ -80,11 +80,11 @@ type FriendDatabase interface {
|
||||
type friendDatabase struct {
|
||||
friend relation.FriendModelInterface
|
||||
friendRequest relation.FriendRequestModelInterface
|
||||
tx tx.CtxTx
|
||||
tx tx.Tx
|
||||
cache cache.FriendCache
|
||||
}
|
||||
|
||||
func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.CtxTx) FriendDatabase {
|
||||
func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relation.FriendRequestModelInterface, cache cache.FriendCache, tx tx.Tx) FriendDatabase {
|
||||
return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx}
|
||||
}
|
||||
|
||||
@@ -106,8 +106,8 @@ func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (
|
||||
}
|
||||
|
||||
// Check if userID2 is in userID1's friend list and vice versa
|
||||
inUser1Friends = utils.IsContain(userID2, userID1FriendIDs)
|
||||
inUser2Friends = utils.IsContain(userID1, userID2FriendIDs)
|
||||
inUser1Friends = datautil.Contain(userID2, userID1FriendIDs...)
|
||||
inUser2Friends = datautil.Contain(userID1, userID2FriendIDs...)
|
||||
return inUser1Friends, inUser2Friends, nil
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUse
|
||||
func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) {
|
||||
return f.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
cache := f.cache.NewCache()
|
||||
// User find friends
|
||||
// user find friends
|
||||
fs1, err := f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -148,7 +148,7 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string,
|
||||
for _, v := range friendUserIDs {
|
||||
fs1 = append(fs1, &relation.FriendModel{OwnerUserID: ownerUserID, FriendUserID: v, AddSource: addSource, OperatorUserID: opUserID})
|
||||
}
|
||||
fs11 := utils.DistinctAny(fs1, func(e *relation.FriendModel) string {
|
||||
fs11 := datautil.DistinctAny(fs1, func(e *relation.FriendModel) string {
|
||||
return e.FriendUserID
|
||||
})
|
||||
|
||||
@@ -165,7 +165,7 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string,
|
||||
fs2 = append(fs2, &relation.FriendModel{OwnerUserID: v, FriendUserID: ownerUserID, AddSource: addSource, OperatorUserID: opUserID})
|
||||
newFriendIDs = append(newFriendIDs, v)
|
||||
}
|
||||
fs22 := utils.DistinctAny(fs2, func(e *relation.FriendModel) string {
|
||||
fs22 := datautil.DistinctAny(fs2, func(e *relation.FriendModel) string {
|
||||
return e.OwnerUserID
|
||||
})
|
||||
err = f.friend.Create(ctx, fs22)
|
||||
@@ -212,14 +212,13 @@ func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest
|
||||
// AgreeFriendRequest accepts a friend request. It first checks for an existing, unprocessed request.
|
||||
func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
|
||||
return f.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
defer log.ZDebug(ctx, "return line")
|
||||
now := time.Now()
|
||||
fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fr.HandleResult != 0 {
|
||||
return errs.ErrArgs.Wrap("the friend request has been processed")
|
||||
return errs.ErrArgs.WrapMsg("the friend request has been processed")
|
||||
}
|
||||
friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx)
|
||||
friendRequest.HandleResult = constant.FriendResponseAgree
|
||||
@@ -246,7 +245,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string {
|
||||
existsMap := datautil.SliceSet(datautil.Slice(exists, func(friend *relation.FriendModel) [2]string {
|
||||
return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend
|
||||
}))
|
||||
var adds []*relation.FriendModel
|
||||
|
||||
@@ -16,15 +16,16 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/OpenIMSDK/tools/tx"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/dtm-labs/rockscache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/db/tx"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
@@ -107,10 +108,11 @@ type GroupDatabase interface {
|
||||
|
||||
func NewGroupDatabase(
|
||||
rdb redis.UniversalClient,
|
||||
localCache *config.LocalCache,
|
||||
groupDB relationtb.GroupModelInterface,
|
||||
groupMemberDB relationtb.GroupMemberModelInterface,
|
||||
groupRequestDB relationtb.GroupRequestModelInterface,
|
||||
ctxTx tx.CtxTx,
|
||||
ctxTx tx.Tx,
|
||||
groupHash cache.GroupHash,
|
||||
) GroupDatabase {
|
||||
rcOptions := rockscache.NewDefaultOptions()
|
||||
@@ -121,7 +123,7 @@ func NewGroupDatabase(
|
||||
groupMemberDB: groupMemberDB,
|
||||
groupRequestDB: groupRequestDB,
|
||||
ctxTx: ctxTx,
|
||||
cache: cache.NewGroupCacheRedis(rdb, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions),
|
||||
cache: cache.NewGroupCacheRedis(rdb, localCache, groupDB, groupMemberDB, groupRequestDB, groupHash, rcOptions),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@ type groupDatabase struct {
|
||||
groupDB relationtb.GroupModelInterface
|
||||
groupMemberDB relationtb.GroupMemberModelInterface
|
||||
groupRequestDB relationtb.GroupRequestModelInterface
|
||||
ctxTx tx.CtxTx
|
||||
ctxTx tx.Tx
|
||||
cache cache.GroupCache
|
||||
}
|
||||
|
||||
@@ -270,7 +272,7 @@ func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pag
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
for _, groupID := range utils.Paginate(groupIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) {
|
||||
for _, groupID := range datautil.Paginate(groupIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber())) {
|
||||
groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, []string{userID})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -285,7 +287,7 @@ func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string,
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
pageIDs := utils.Paginate(groupMemberIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber()))
|
||||
pageIDs := datautil.Paginate(groupMemberIDs, int(pagination.GetPageNumber()), int(pagination.GetShowNumber()))
|
||||
if len(pageIDs) == 0 {
|
||||
return int64(len(groupMemberIDs)), nil, nil
|
||||
}
|
||||
|
||||
+222
-192
@@ -18,21 +18,22 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
pbmsg "github.com/OpenIMSDK/protocol/msg"
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"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/convert"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
pbmsg "github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mq/kafka"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"github.com/openimsdk/tools/utils/timeutil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
@@ -47,7 +48,7 @@ type CommonMsgDatabase interface {
|
||||
// BatchInsertChat2DB inserts a batch of messages into the database for a specific conversation.
|
||||
BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error
|
||||
// RevokeMsg revokes a message in a conversation.
|
||||
RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error
|
||||
RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error
|
||||
// MarkSingleChatMsgsAsRead marks messages as read for a single chat by sequence numbers.
|
||||
MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error
|
||||
// DeleteMessagesFromCache deletes message caches from Redis by sequence numbers.
|
||||
@@ -100,75 +101,58 @@ type CommonMsgDatabase interface {
|
||||
MsgToPushMQ(ctx context.Context, key, conversarionID string, msg2mq *sdkws.MsgData) (int32, int64, error)
|
||||
MsgToMongoMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData, lastSeq int64) error
|
||||
|
||||
RangeUserSendCount(
|
||||
ctx context.Context,
|
||||
start time.Time,
|
||||
end time.Time,
|
||||
group bool,
|
||||
ase bool,
|
||||
pageNumber int32,
|
||||
showNumber int32,
|
||||
) (msgCount int64, userCount int64, users []*unrelationtb.UserCount, dateCount map[string]int64, err error)
|
||||
RangeGroupSendCount(
|
||||
ctx context.Context,
|
||||
start time.Time,
|
||||
end time.Time,
|
||||
ase bool,
|
||||
pageNumber int32,
|
||||
showNumber int32,
|
||||
) (msgCount int64, userCount int64, groups []*unrelationtb.GroupCount, dateCount map[string]int64, err error)
|
||||
RangeUserSendCount(ctx context.Context, start time.Time, end time.Time, group bool, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error)
|
||||
RangeGroupSendCount(ctx context.Context, start time.Time, end time.Time, ase bool, pageNumber int32, showNumber int32) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error)
|
||||
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
|
||||
|
||||
// clear msg
|
||||
GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error)
|
||||
DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error)
|
||||
}
|
||||
|
||||
func NewCommonMsgDatabase(msgDocModel unrelationtb.MsgDocModelInterface, cacheModel cache.MsgModel, config *config.GlobalConfig) (CommonMsgDatabase, error) {
|
||||
producerConfig := &kafka.ProducerConfig{
|
||||
ProducerAck: config.Kafka.ProducerAck,
|
||||
CompressType: config.Kafka.CompressType,
|
||||
Username: config.Kafka.Username,
|
||||
Password: config.Kafka.Password,
|
||||
}
|
||||
|
||||
var tlsConfig *kafka.TLSConfig
|
||||
if config.Kafka.TLS != nil {
|
||||
tlsConfig = &kafka.TLSConfig{
|
||||
CACrt: config.Kafka.TLS.CACrt,
|
||||
ClientCrt: config.Kafka.TLS.ClientCrt,
|
||||
ClientKey: config.Kafka.TLS.ClientKey,
|
||||
ClientKeyPwd: config.Kafka.TLS.ClientKeyPwd,
|
||||
InsecureSkipVerify: false,
|
||||
}
|
||||
}
|
||||
producerToRedis, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.LatestMsgToRedis.Topic, producerConfig, tlsConfig)
|
||||
func NewCommonMsgDatabase(msgDocModel relation.MsgDocModelInterface, msg cache.MsgCache, seq cache.SeqCache, kafkaConf *config.Kafka) (CommonMsgDatabase, error) {
|
||||
conf, err := kafka.BuildProducerConfig(*kafkaConf.Build())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
producerToMongo, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToMongo.Topic, producerConfig, tlsConfig)
|
||||
producerToRedis, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToRedisTopic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
producerToPush, err := kafka.NewKafkaProducer(config.Kafka.Addr, config.Kafka.MsgToPush.Topic, producerConfig, tlsConfig)
|
||||
producerToMongo, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToMongoTopic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
producerToPush, err := kafka.NewKafkaProducer(conf, kafkaConf.Address, kafkaConf.ToPushTopic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &commonMsgDatabase{
|
||||
msgDocDatabase: msgDocModel,
|
||||
cache: cacheModel,
|
||||
msg: msg,
|
||||
seq: seq,
|
||||
producer: producerToRedis,
|
||||
producerToMongo: producerToMongo,
|
||||
producerToPush: producerToPush,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *config.GlobalConfig) (CommonMsgDatabase, error) {
|
||||
cacheModel := cache.NewMsgCacheModel(rdb, config)
|
||||
msgDocModel := unrelation.NewMsgMongoDriver(database)
|
||||
return NewCommonMsgDatabase(msgDocModel, cacheModel, config)
|
||||
}
|
||||
//func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database, config *tools.CronTaskConfig) (CommonMsgDatabase, error) {
|
||||
// msgDocModel, err := mgo.NewMsgMongo(database)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// //todo MsgCacheTimeout
|
||||
// msg := cache.NewMsgCache(rdb, 86400, config.RedisConfig.EnablePipeline)
|
||||
// seq := cache.NewSeqCache(rdb)
|
||||
// return NewCommonMsgDatabase(msgDocModel, msg, seq, &config.KafkaConfig)
|
||||
//}
|
||||
|
||||
type commonMsgDatabase struct {
|
||||
msgDocDatabase unrelationtb.MsgDocModelInterface
|
||||
msg unrelationtb.MsgDocModel
|
||||
cache cache.MsgModel
|
||||
msgDocDatabase relation.MsgDocModelInterface
|
||||
msgTable relation.MsgDocModel
|
||||
msg cache.MsgCache
|
||||
seq cache.SeqCache
|
||||
producer *kafka.Producer
|
||||
producerToMongo *kafka.Producer
|
||||
producerToModify *kafka.Producer
|
||||
@@ -209,24 +193,24 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
num := db.msg.GetSingleGocMsgNum()
|
||||
num := db.msgTable.GetSingleGocMsgNum()
|
||||
// num = 100
|
||||
for i, field := range fields { // Check the type of the field
|
||||
var ok bool
|
||||
switch key {
|
||||
case updateKeyMsg:
|
||||
var msg *unrelationtb.MsgDataModel
|
||||
msg, ok = field.(*unrelationtb.MsgDataModel)
|
||||
var msg *relation.MsgDataModel
|
||||
msg, ok = field.(*relation.MsgDataModel)
|
||||
if msg != nil && msg.Seq != firstSeq+int64(i) {
|
||||
return errs.ErrInternalServer.Wrap("seq is invalid")
|
||||
return errs.ErrInternalServer.WrapMsg("seq is invalid")
|
||||
}
|
||||
case updateKeyRevoke:
|
||||
_, ok = field.(*unrelationtb.RevokeModel)
|
||||
_, ok = field.(*relation.RevokeModel)
|
||||
default:
|
||||
return errs.ErrInternalServer.Wrap("key is invalid")
|
||||
return errs.ErrInternalServer.WrapMsg("key is invalid")
|
||||
}
|
||||
if !ok {
|
||||
return errs.ErrInternalServer.Wrap("field type is invalid")
|
||||
return errs.ErrInternalServer.WrapMsg("field type is invalid")
|
||||
}
|
||||
}
|
||||
// Returns true if the document exists in the database, false if the document does not exist in the database
|
||||
@@ -235,8 +219,8 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
res *mongo.UpdateResult
|
||||
err error
|
||||
)
|
||||
docID := db.msg.GetDocID(conversationID, seq)
|
||||
index := db.msg.GetMsgIndex(seq)
|
||||
docID := db.msgTable.GetDocID(conversationID, seq)
|
||||
index := db.msgTable.GetMsgIndex(seq)
|
||||
field := fields[i]
|
||||
switch key {
|
||||
case updateKeyMsg:
|
||||
@@ -261,31 +245,31 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
continue // The current data has been updated, skip the current data
|
||||
}
|
||||
}
|
||||
doc := unrelationtb.MsgDocModel{
|
||||
DocID: db.msg.GetDocID(conversationID, seq),
|
||||
Msg: make([]*unrelationtb.MsgInfoModel, num),
|
||||
doc := relation.MsgDocModel{
|
||||
DocID: db.msgTable.GetDocID(conversationID, seq),
|
||||
Msg: make([]*relation.MsgInfoModel, num),
|
||||
}
|
||||
var insert int // Inserted data number
|
||||
for j := i; j < len(fields); j++ {
|
||||
seq = firstSeq + int64(j)
|
||||
if db.msg.GetDocID(conversationID, seq) != doc.DocID {
|
||||
if db.msgTable.GetDocID(conversationID, seq) != doc.DocID {
|
||||
break
|
||||
}
|
||||
insert++
|
||||
switch key {
|
||||
case updateKeyMsg:
|
||||
doc.Msg[db.msg.GetMsgIndex(seq)] = &unrelationtb.MsgInfoModel{
|
||||
Msg: fields[j].(*unrelationtb.MsgDataModel),
|
||||
doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{
|
||||
Msg: fields[j].(*relation.MsgDataModel),
|
||||
}
|
||||
case updateKeyRevoke:
|
||||
doc.Msg[db.msg.GetMsgIndex(seq)] = &unrelationtb.MsgInfoModel{
|
||||
Revoke: fields[j].(*unrelationtb.RevokeModel),
|
||||
doc.Msg[db.msgTable.GetMsgIndex(seq)] = &relation.MsgInfoModel{
|
||||
Revoke: fields[j].(*relation.RevokeModel),
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, model := range doc.Msg {
|
||||
if model == nil {
|
||||
model = &unrelationtb.MsgInfoModel{}
|
||||
model = &relation.MsgInfoModel{}
|
||||
doc.Msg[i] = model
|
||||
}
|
||||
if model.DelList == nil {
|
||||
@@ -308,16 +292,16 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
|
||||
func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversationID string, msgList []*sdkws.MsgData, currentMaxSeq int64) error {
|
||||
if len(msgList) == 0 {
|
||||
return errs.ErrArgs.Wrap("msgList is empty")
|
||||
return errs.ErrArgs.WrapMsg("msgList is empty")
|
||||
}
|
||||
msgs := make([]any, len(msgList))
|
||||
for i, msg := range msgList {
|
||||
if msg == nil {
|
||||
continue
|
||||
}
|
||||
var offlinePushModel *unrelationtb.OfflinePushModel
|
||||
var offlinePushModel *relation.OfflinePushModel
|
||||
if msg.OfflinePushInfo != nil {
|
||||
offlinePushModel = &unrelationtb.OfflinePushModel{
|
||||
offlinePushModel = &relation.OfflinePushModel{
|
||||
Title: msg.OfflinePushInfo.Title,
|
||||
Desc: msg.OfflinePushInfo.Desc,
|
||||
Ex: msg.OfflinePushInfo.Ex,
|
||||
@@ -325,7 +309,7 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio
|
||||
IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount,
|
||||
}
|
||||
}
|
||||
msgs[i] = &unrelationtb.MsgDataModel{
|
||||
msgs[i] = &relation.MsgDataModel{
|
||||
SendID: msg.SendID,
|
||||
RecvID: msg.RecvID,
|
||||
GroupID: msg.GroupID,
|
||||
@@ -352,15 +336,15 @@ func (db *commonMsgDatabase) BatchInsertChat2DB(ctx context.Context, conversatio
|
||||
return db.BatchInsertBlock(ctx, conversationID, msgs, updateKeyMsg, msgList[0].Seq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unrelationtb.RevokeModel) error {
|
||||
func (db *commonMsgDatabase) RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *relation.RevokeModel) error {
|
||||
return db.BatchInsertBlock(ctx, conversationID, []any{revoke}, updateKeyRevoke, seq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, totalSeqs []int64) error {
|
||||
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, totalSeqs) {
|
||||
for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, totalSeqs) {
|
||||
var indexes []int64
|
||||
for _, seq := range seqs {
|
||||
indexes = append(indexes, db.msg.GetMsgIndex(seq))
|
||||
indexes = append(indexes, db.msgTable.GetMsgIndex(seq))
|
||||
}
|
||||
log.ZDebug(ctx, "MarkSingleChatMsgsAsRead", "userID", userID, "docID", docID, "indexes", indexes)
|
||||
if err := db.msgDocDatabase.MarkSingleChatMsgsAsRead(ctx, userID, docID, indexes); err != nil {
|
||||
@@ -372,25 +356,25 @@ func (db *commonMsgDatabase) MarkSingleChatMsgsAsRead(ctx context.Context, userI
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error {
|
||||
return db.cache.DeleteMessages(ctx, conversationID, seqs)
|
||||
return db.msg.DeleteMessages(ctx, conversationID, seqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) {
|
||||
db.cache.DelUserDeleteMsgsList(ctx, conversationID, seqs)
|
||||
db.msg.DelUserDeleteMsgsList(ctx, conversationID, seqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNew bool, err error) {
|
||||
currentMaxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
|
||||
currentMaxSeq, err := db.seq.GetMaxSeq(ctx, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
log.ZError(ctx, "db.cache.GetMaxSeq", err)
|
||||
log.ZError(ctx, "db.seq.GetMaxSeq", err)
|
||||
return 0, false, err
|
||||
}
|
||||
lenList := len(msgs)
|
||||
if int64(lenList) > db.msg.GetSingleGocMsgNum() {
|
||||
return 0, false, errors.New("too large")
|
||||
if int64(lenList) > db.msgTable.GetSingleGocMsgNum() {
|
||||
return 0, false, errs.New("message count exceeds limit", "limit", db.msgTable.GetSingleGocMsgNum()).Wrap()
|
||||
}
|
||||
if lenList < 1 {
|
||||
return 0, false, errors.New("too short as 0")
|
||||
return 0, false, errs.New("no messages to insert", "minCount", 1).Wrap()
|
||||
}
|
||||
if errs.Unwrap(err) == redis.Nil {
|
||||
isNew = true
|
||||
@@ -402,19 +386,22 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa
|
||||
m.Seq = currentMaxSeq
|
||||
userSeqMap[m.SendID] = m.Seq
|
||||
}
|
||||
failedNum, err := db.cache.SetMessageToCache(ctx, conversationID, msgs)
|
||||
|
||||
failedNum, err := db.msg.SetMessageToCache(ctx, conversationID, msgs)
|
||||
if err != nil {
|
||||
prommetrics.MsgInsertRedisFailedCounter.Add(float64(failedNum))
|
||||
log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID)
|
||||
} else {
|
||||
prommetrics.MsgInsertRedisSuccessCounter.Inc()
|
||||
}
|
||||
err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq)
|
||||
|
||||
err = db.seq.SetMaxSeq(ctx, conversationID, currentMaxSeq)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "db.cache.SetMaxSeq error", err, "conversationID", conversationID)
|
||||
log.ZError(ctx, "db.seq.SetMaxSeq error", err, "conversationID", conversationID)
|
||||
prommetrics.SeqSetFailedCounter.Inc()
|
||||
}
|
||||
err = db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap)
|
||||
|
||||
err = db.seq.SetHasReadSeqs(ctx, conversationID, userSeqMap)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "SetHasReadSeqs error", err, "userSeqMap", userSeqMap, "conversationID", conversationID)
|
||||
prommetrics.SeqSetFailedCounter.Inc()
|
||||
@@ -423,7 +410,7 @@ func (db *commonMsgDatabase) BatchInsertChat2Cache(ctx context.Context, conversa
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversationID string, seqs []int64) (totalMsgs []*sdkws.MsgData, err error) {
|
||||
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, seqs) {
|
||||
for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, seqs) {
|
||||
// log.ZDebug(ctx, "getMsgBySeqs", "docID", docID, "seqs", seqs)
|
||||
msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, conversationID, seqs)
|
||||
if err != nil {
|
||||
@@ -436,7 +423,7 @@ func (db *commonMsgDatabase) getMsgBySeqs(ctx context.Context, userID, conversat
|
||||
return totalMsgs, nil
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*unrelationtb.MsgInfoModel, userID, conversationID string, msg *unrelationtb.MsgInfoModel) {
|
||||
func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][]*relation.MsgInfoModel, userID, conversationID string, msg *relation.MsgInfoModel) {
|
||||
if msg.IsRead {
|
||||
msg.Msg.IsRead = true
|
||||
}
|
||||
@@ -458,12 +445,12 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][
|
||||
if quoteMsg.QuoteMessage == nil || quoteMsg.QuoteMessage.ContentType == constant.MsgRevokeNotification {
|
||||
return
|
||||
}
|
||||
var msgs []*unrelationtb.MsgInfoModel
|
||||
var msgs []*relation.MsgInfoModel
|
||||
if v, ok := cache[quoteMsg.QuoteMessage.Seq]; ok {
|
||||
msgs = v
|
||||
} else {
|
||||
if quoteMsg.QuoteMessage.Seq > 0 {
|
||||
ms, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, db.msg.GetDocID(conversationID, quoteMsg.QuoteMessage.Seq), []int64{quoteMsg.QuoteMessage.Seq})
|
||||
ms, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, db.msgTable.GetDocID(conversationID, quoteMsg.QuoteMessage.Seq), []int64{quoteMsg.QuoteMessage.Seq})
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GetMsgBySeqIndexIn1Doc", err, "conversationID", conversationID, "seq", quoteMsg.QuoteMessage.Seq)
|
||||
return
|
||||
@@ -487,17 +474,17 @@ func (db *commonMsgDatabase) handlerDBMsg(ctx context.Context, cache map[int64][
|
||||
return
|
||||
}
|
||||
msg.Msg.Content = string(data)
|
||||
if _, err := db.msgDocDatabase.UpdateMsg(ctx, db.msg.GetDocID(conversationID, msg.Msg.Seq), db.msg.GetMsgIndex(msg.Msg.Seq), "msg", msg.Msg); err != nil {
|
||||
if _, err := db.msgDocDatabase.UpdateMsg(ctx, db.msgTable.GetDocID(conversationID, msg.Msg.Seq), db.msgTable.GetMsgIndex(msg.Msg.Seq), "msg", msg.Msg); err != nil {
|
||||
log.ZError(ctx, "UpdateMsgContent", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*unrelationtb.MsgInfoModel, err error) {
|
||||
func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, conversationID string, seqs []int64) (totalMsgs []*relation.MsgInfoModel, err error) {
|
||||
msgs, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, docID, seqs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempCache := make(map[int64][]*unrelationtb.MsgInfoModel)
|
||||
tempCache := make(map[int64][]*relation.MsgInfoModel)
|
||||
for _, msg := range msgs {
|
||||
db.handlerDBMsg(ctx, tempCache, userID, conversationID, msg)
|
||||
}
|
||||
@@ -506,7 +493,7 @@ func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID
|
||||
|
||||
func (db *commonMsgDatabase) getMsgBySeqsRange(ctx context.Context, userID string, conversationID string, allSeqs []int64, begin, end int64) (seqMsgs []*sdkws.MsgData, err error) {
|
||||
log.ZDebug(ctx, "getMsgBySeqsRange", "conversationID", conversationID, "allSeqs", allSeqs, "begin", begin, "end", end)
|
||||
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, allSeqs) {
|
||||
for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, allSeqs) {
|
||||
log.ZDebug(ctx, "getMsgBySeqsRange", "docID", docID, "seqs", seqs)
|
||||
msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, conversationID, seqs)
|
||||
if err != nil {
|
||||
@@ -542,23 +529,23 @@ func (db *commonMsgDatabase) getMsgBySeqsRange(ctx context.Context, userID strin
|
||||
// "userMinSeq" can be set as the same value as the conversation's "maxSeq" at the moment they join the group.
|
||||
// This ensures that their message retrieval starts from the point they joined.
|
||||
func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (int64, int64, []*sdkws.MsgData, error) {
|
||||
userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
userMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
minSeq, err := db.cache.GetMinSeq(ctx, conversationID)
|
||||
minSeq, err := db.seq.GetMinSeq(ctx, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
if userMinSeq > minSeq {
|
||||
minSeq = userMinSeq
|
||||
}
|
||||
//"minSeq" represents the startSeq value that the user can retrieve.
|
||||
// "minSeq" represents the startSeq value that the user can retrieve.
|
||||
if minSeq > end {
|
||||
log.ZInfo(ctx, "minSeq > end", "minSeq", minSeq, "end", end)
|
||||
log.ZWarn(ctx, "minSeq > end", errs.New("minSeq>end"), "minSeq", minSeq, "end", end)
|
||||
return 0, 0, nil, nil
|
||||
}
|
||||
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
|
||||
maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
@@ -568,7 +555,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
maxSeq = userMaxSeq
|
||||
}
|
||||
}
|
||||
//"maxSeq" represents the endSeq value that the user can retrieve.
|
||||
// "maxSeq" represents the endSeq value that the user can retrieve.
|
||||
|
||||
if begin < minSeq {
|
||||
begin = minSeq
|
||||
@@ -576,9 +563,9 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
if end > maxSeq {
|
||||
end = maxSeq
|
||||
}
|
||||
//"begin" and "end" represent the actual startSeq and endSeq values that the user can retrieve.
|
||||
// "begin" and "end" represent the actual startSeq and endSeq values that the user can retrieve.
|
||||
if end < begin {
|
||||
return 0, 0, nil, errs.ErrArgs.Wrap("seq end < begin")
|
||||
return 0, 0, nil, errs.ErrArgs.WrapMsg("seq end < begin")
|
||||
}
|
||||
var seqs []int64
|
||||
if end-begin+1 <= num {
|
||||
@@ -591,25 +578,13 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
}
|
||||
}
|
||||
|
||||
//167 178 10
|
||||
//if end-num < {
|
||||
//
|
||||
//}
|
||||
//var seqs []int64
|
||||
//for i := end; i > end-num; i-- {
|
||||
// if i >= begin {
|
||||
// seqs = append([]int64{i}, seqs...)
|
||||
// } else {
|
||||
// break
|
||||
// }
|
||||
//}
|
||||
if len(seqs) == 0 {
|
||||
return 0, 0, nil, nil
|
||||
}
|
||||
newBegin := seqs[0]
|
||||
newEnd := seqs[len(seqs)-1]
|
||||
log.ZDebug(ctx, "GetMsgBySeqsRange", "first seqs", seqs, "newBegin", newBegin, "newEnd", newEnd)
|
||||
cachedMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, seqs)
|
||||
cachedMsgs, failedSeqs, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs)
|
||||
if err != nil {
|
||||
if err != redis.Nil {
|
||||
|
||||
@@ -618,13 +593,13 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
}
|
||||
var successMsgs []*sdkws.MsgData
|
||||
if len(cachedMsgs) > 0 {
|
||||
delSeqs, err := db.cache.GetUserDelList(ctx, userID, conversationID)
|
||||
delSeqs, err := db.msg.GetUserDelList(ctx, userID, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
var cacheDelNum int
|
||||
for _, msg := range cachedMsgs {
|
||||
if !utils.Contain(msg.Seq, delSeqs...) {
|
||||
if !datautil.Contain(msg.Seq, delSeqs...) {
|
||||
successMsgs = append(successMsgs, msg)
|
||||
} else {
|
||||
cacheDelNum += 1
|
||||
@@ -635,7 +610,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
for i := 1; i <= cacheDelNum; {
|
||||
newSeq := newBegin - int64(i)
|
||||
if newSeq >= begin {
|
||||
if !utils.Contain(newSeq, delSeqs...) {
|
||||
if !datautil.Contain(newSeq, delSeqs...) {
|
||||
log.ZDebug(ctx, "seq del in cache, a new seq in range append", "new seq", newSeq)
|
||||
reGetSeqsCache = append(reGetSeqsCache, newSeq)
|
||||
i++
|
||||
@@ -646,7 +621,7 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
}
|
||||
if len(reGetSeqsCache) > 0 {
|
||||
log.ZDebug(ctx, "reGetSeqsCache", "reGetSeqsCache", reGetSeqsCache)
|
||||
cachedMsgs, failedSeqs2, err := db.cache.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache)
|
||||
cachedMsgs, failedSeqs2, err := db.msg.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache)
|
||||
if err != nil {
|
||||
if err != redis.Nil {
|
||||
|
||||
@@ -676,15 +651,15 @@ func (db *commonMsgDatabase) GetMsgBySeqsRange(ctx context.Context, userID strin
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (int64, int64, []*sdkws.MsgData, error) {
|
||||
userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
userMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
minSeq, err := db.cache.GetMinSeq(ctx, conversationID)
|
||||
minSeq, err := db.seq.GetMinSeq(ctx, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
|
||||
maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
@@ -697,28 +672,14 @@ func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, co
|
||||
newSeqs = append(newSeqs, seq)
|
||||
}
|
||||
}
|
||||
successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs)
|
||||
successMsgs, failedSeqs, err := db.msg.GetMessagesBySeq(ctx, conversationID, newSeqs)
|
||||
if err != nil {
|
||||
if err != redis.Nil {
|
||||
log.ZError(ctx, "get message from redis exception", err, "failedSeqs", failedSeqs, "conversationID", conversationID)
|
||||
}
|
||||
}
|
||||
log.ZInfo(
|
||||
ctx,
|
||||
"db.cache.GetMessagesBySeq",
|
||||
"userID",
|
||||
userID,
|
||||
"conversationID",
|
||||
conversationID,
|
||||
"seqs",
|
||||
seqs,
|
||||
"successMsgs",
|
||||
len(successMsgs),
|
||||
"failedSeqs",
|
||||
failedSeqs,
|
||||
"conversationID",
|
||||
conversationID,
|
||||
)
|
||||
log.ZDebug(ctx, "db.seq.GetMessagesBySeq", "userID", userID, "conversationID", conversationID, "seqs",
|
||||
seqs, "len(successMsgs)", len(successMsgs), "failedSeqs", failedSeqs)
|
||||
|
||||
if len(failedSeqs) > 0 {
|
||||
mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs)
|
||||
@@ -739,17 +700,17 @@ func (db *commonMsgDatabase) DeleteConversationMsgsAndSetMinSeq(ctx context.Cont
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.ZInfo(ctx, "DeleteConversationMsgsAndSetMinSeq", "conversationID", conversationID, "minSeq", minSeq)
|
||||
log.ZDebug(ctx, "DeleteConversationMsgsAndSetMinSeq", "conversationID", conversationID, "minSeq", minSeq)
|
||||
if minSeq == 0 {
|
||||
return nil
|
||||
}
|
||||
if remainTime == 0 {
|
||||
err = db.cache.CleanUpOneConversationAllMsg(ctx, conversationID)
|
||||
err = db.msg.CleanUpOneConversationAllMsg(ctx, conversationID)
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "CleanUpOneUserAllMsg", err, "conversationID", conversationID)
|
||||
}
|
||||
}
|
||||
return db.cache.SetMinSeq(ctx, conversationID, minSeq)
|
||||
return db.seq.SetMinSeq(ctx, conversationID, minSeq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string, conversationID string, destructTime int64, lastMsgDestructTime time.Time) (seqs []int64, err error) {
|
||||
@@ -759,7 +720,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string
|
||||
msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1)
|
||||
if err != nil || msgDocModel.DocID == "" {
|
||||
if err != nil {
|
||||
if err == unrelation.ErrMsgListNotExist {
|
||||
if err == relation.ErrMsgListNotExist {
|
||||
log.ZDebug(ctx, "not doc find", "conversationID", conversationID, "userID", userID, "index", index)
|
||||
} else {
|
||||
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
|
||||
@@ -769,14 +730,14 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string
|
||||
break
|
||||
}
|
||||
index++
|
||||
//&& msgDocModel.Msg[0].Msg.SendTime > lastMsgDestructTime.UnixMilli()
|
||||
// && msgDocModel.Msg[0].Msg.SendTime > lastMsgDestructTime.UnixMilli()
|
||||
if len(msgDocModel.Msg) > 0 {
|
||||
i := 0
|
||||
var over bool
|
||||
for _, msg := range msgDocModel.Msg {
|
||||
i++
|
||||
if msg != nil && msg.Msg != nil && msg.Msg.SendTime+destructTime*1000 <= time.Now().UnixMilli() {
|
||||
if msg.Msg.SendTime+destructTime*1000 > lastMsgDestructTime.UnixMilli() && !utils.Contain(userID, msg.DelList...) {
|
||||
if msg.Msg.SendTime+destructTime*1000 > lastMsgDestructTime.UnixMilli() && !datautil.Contain(userID, msg.DelList...) {
|
||||
seqs = append(seqs, msg.Msg.Seq)
|
||||
}
|
||||
} else {
|
||||
@@ -794,12 +755,12 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string
|
||||
log.ZDebug(ctx, "UserMsgsDestruct", "conversationID", conversationID, "userID", userID, "seqs", seqs)
|
||||
if len(seqs) > 0 {
|
||||
userMinSeq := seqs[len(seqs)-1] + 1
|
||||
currentUserMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
currentUserMinSeq, err := db.seq.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
return nil, err
|
||||
}
|
||||
if currentUserMinSeq < userMinSeq {
|
||||
if err := db.cache.SetConversationUserMinSeq(ctx, conversationID, userID, userMinSeq); err != nil {
|
||||
if err := db.seq.SetConversationUserMinSeq(ctx, conversationID, userID, userMinSeq); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -826,7 +787,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
|
||||
msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1)
|
||||
if err != nil || msgDocModel.DocID == "" {
|
||||
if err != nil {
|
||||
if err == unrelation.ErrMsgListNotExist {
|
||||
if err == relation.ErrMsgListNotExist {
|
||||
log.ZDebug(ctx, "deleteMsgRecursion ErrMsgListNotExist", "conversationID", conversationID, "index:", index)
|
||||
} else {
|
||||
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
|
||||
@@ -840,10 +801,10 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
|
||||
return delStruct.getSetMinSeq() + 1, nil
|
||||
}
|
||||
log.ZDebug(ctx, "doc info", "conversationID", conversationID, "index", index, "docID", msgDocModel.DocID, "len", len(msgDocModel.Msg))
|
||||
if int64(len(msgDocModel.Msg)) > db.msg.GetSingleGocMsgNum() {
|
||||
if int64(len(msgDocModel.Msg)) > db.msgTable.GetSingleGocMsgNum() {
|
||||
log.ZWarn(ctx, "msgs too large", nil, "length", len(msgDocModel.Msg), "docID:", msgDocModel.DocID)
|
||||
}
|
||||
if msgDocModel.IsFull() && msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.SendTime+(remainTime*1000) < utils.GetCurrentTimestampByMill() {
|
||||
if msgDocModel.IsFull() && msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.SendTime+(remainTime*1000) < timeutil.GetCurrentTimestampByMill() {
|
||||
log.ZDebug(ctx, "doc is full and all msg is expired", "docID", msgDocModel.DocID)
|
||||
delStruct.delDocIDs = append(delStruct.delDocIDs, msgDocModel.DocID)
|
||||
delStruct.minSeq = msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.Seq
|
||||
@@ -851,7 +812,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
|
||||
var delMsgIndexs []int
|
||||
for i, MsgInfoModel := range msgDocModel.Msg {
|
||||
if MsgInfoModel != nil && MsgInfoModel.Msg != nil {
|
||||
if utils.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) {
|
||||
if timeutil.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) {
|
||||
delMsgIndexs = append(delMsgIndexs, i)
|
||||
}
|
||||
}
|
||||
@@ -868,13 +829,13 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, allSeqs []int64) error {
|
||||
if err := db.cache.DeleteMessages(ctx, conversationID, allSeqs); err != nil {
|
||||
if err := db.msg.DeleteMessages(ctx, conversationID, allSeqs); err != nil {
|
||||
return err
|
||||
}
|
||||
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, allSeqs) {
|
||||
for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, allSeqs) {
|
||||
var indexes []int
|
||||
for _, seq := range seqs {
|
||||
indexes = append(indexes, int(db.msg.GetMsgIndex(seq)))
|
||||
indexes = append(indexes, int(db.msgTable.GetMsgIndex(seq)))
|
||||
}
|
||||
if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, docID, indexes); err != nil {
|
||||
return err
|
||||
@@ -884,7 +845,7 @@ func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conve
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error {
|
||||
cachedMsgs, _, err := db.cache.GetMessagesBySeq(ctx, conversationID, seqs)
|
||||
cachedMsgs, _, err := db.msg.GetMessagesBySeq(ctx, conversationID, seqs)
|
||||
if err != nil && errs.Unwrap(err) != redis.Nil {
|
||||
log.ZWarn(ctx, "DeleteUserMsgsBySeqs", err, "conversationID", conversationID, "seqs", seqs)
|
||||
return err
|
||||
@@ -894,14 +855,14 @@ func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID st
|
||||
for _, msg := range cachedMsgs {
|
||||
cacheSeqs = append(cacheSeqs, msg.Seq)
|
||||
}
|
||||
if err := db.cache.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil {
|
||||
if err := db.msg.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, seqs) {
|
||||
for docID, seqs := range db.msgTable.GetDocIDSeqsMap(conversationID, seqs) {
|
||||
for _, seq := range seqs {
|
||||
if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msg.GetMsgIndex(seq), "del_list", []string{userID}); err != nil {
|
||||
if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msgTable.GetMsgIndex(seq), "del_list", []string{userID}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -915,91 +876,91 @@ func (db *commonMsgDatabase) DeleteMsgsBySeqs(ctx context.Context, conversationI
|
||||
|
||||
func (db *commonMsgDatabase) CleanUpUserConversationsMsgs(ctx context.Context, user string, conversationIDs []string) {
|
||||
for _, conversationID := range conversationIDs {
|
||||
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
|
||||
maxSeq, err := db.seq.GetMaxSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
log.ZInfo(ctx, "max seq is nil", "conversationID", conversationID)
|
||||
log.ZDebug(ctx, "max seq is nil", "conversationID", conversationID)
|
||||
} else {
|
||||
log.ZError(ctx, "get max seq failed", err, "conversationID", conversationID)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := db.cache.SetMinSeq(ctx, conversationID, maxSeq+1); err != nil {
|
||||
if err := db.seq.SetMinSeq(ctx, conversationID, maxSeq+1); err != nil {
|
||||
log.ZError(ctx, "set min seq failed", err, "conversationID", conversationID, "minSeq", maxSeq+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error {
|
||||
return db.cache.SetMaxSeq(ctx, conversationID, maxSeq)
|
||||
return db.seq.SetMaxSeq(ctx, conversationID, maxSeq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
|
||||
return db.cache.GetMaxSeqs(ctx, conversationIDs)
|
||||
return db.seq.GetMaxSeqs(ctx, conversationIDs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) {
|
||||
return db.cache.GetMaxSeq(ctx, conversationID)
|
||||
return db.seq.GetMaxSeq(ctx, conversationID)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
|
||||
return db.cache.SetMinSeq(ctx, conversationID, minSeq)
|
||||
return db.seq.SetMinSeq(ctx, conversationID, minSeq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetMinSeqs(ctx context.Context, seqs map[string]int64) error {
|
||||
return db.cache.SetMinSeqs(ctx, seqs)
|
||||
return db.seq.SetMinSeqs(ctx, seqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
|
||||
return db.cache.GetMinSeqs(ctx, conversationIDs)
|
||||
return db.seq.GetMinSeqs(ctx, conversationIDs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetMinSeq(ctx context.Context, conversationID string) (int64, error) {
|
||||
return db.cache.GetMinSeq(ctx, conversationID)
|
||||
return db.seq.GetMinSeq(ctx, conversationID)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
|
||||
return db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
return db.seq.GetConversationUserMinSeq(ctx, conversationID, userID)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetConversationUserMinSeqs(ctx context.Context, conversationID string, userIDs []string) (map[string]int64, error) {
|
||||
return db.cache.GetConversationUserMinSeqs(ctx, conversationID, userIDs)
|
||||
return db.seq.GetConversationUserMinSeqs(ctx, conversationID, userIDs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error {
|
||||
return db.cache.SetConversationUserMinSeq(ctx, conversationID, userID, minSeq)
|
||||
return db.seq.SetConversationUserMinSeq(ctx, conversationID, userID, minSeq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error) {
|
||||
return db.cache.SetConversationUserMinSeqs(ctx, conversationID, seqs)
|
||||
return db.seq.SetConversationUserMinSeqs(ctx, conversationID, seqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error {
|
||||
return db.cache.SetUserConversationsMinSeqs(ctx, userID, seqs)
|
||||
return db.seq.SetUserConversationsMinSeqs(ctx, userID, seqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error {
|
||||
return db.cache.UserSetHasReadSeqs(ctx, userID, hasReadSeqs)
|
||||
return db.seq.UserSetHasReadSeqs(ctx, userID, hasReadSeqs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error {
|
||||
return db.cache.SetHasReadSeq(ctx, userID, conversationID, hasReadSeq)
|
||||
return db.seq.SetHasReadSeq(ctx, userID, conversationID, hasReadSeq)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) {
|
||||
return db.cache.GetHasReadSeqs(ctx, userID, conversationIDs)
|
||||
return db.seq.GetHasReadSeqs(ctx, userID, conversationIDs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) {
|
||||
return db.cache.GetHasReadSeq(ctx, userID, conversationID)
|
||||
return db.seq.GetHasReadSeq(ctx, userID, conversationID)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) SetSendMsgStatus(ctx context.Context, id string, status int32) error {
|
||||
return db.cache.SetSendMsgStatus(ctx, id, status)
|
||||
return db.msg.SetSendMsgStatus(ctx, id, status)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetSendMsgStatus(ctx context.Context, id string) (int32, error) {
|
||||
return db.cache.GetSendMsgStatus(ctx, id)
|
||||
return db.msg.GetSendMsgStatus(ctx, id)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetConversationMinMaxSeqInMongoAndCache(ctx context.Context, conversationID string) (minSeqMongo, maxSeqMongo, minSeqCache, maxSeqCache int64, err error) {
|
||||
@@ -1007,11 +968,11 @@ func (db *commonMsgDatabase) GetConversationMinMaxSeqInMongoAndCache(ctx context
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
minSeqCache, err = db.cache.GetMinSeq(ctx, conversationID)
|
||||
minSeqCache, err = db.seq.GetMinSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
maxSeqCache, err = db.cache.GetMaxSeq(ctx, conversationID)
|
||||
maxSeqCache, err = db.seq.GetMaxSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -1044,7 +1005,7 @@ func (db *commonMsgDatabase) RangeUserSendCount(
|
||||
ase bool,
|
||||
pageNumber int32,
|
||||
showNumber int32,
|
||||
) (msgCount int64, userCount int64, users []*unrelationtb.UserCount, dateCount map[string]int64, err error) {
|
||||
) (msgCount int64, userCount int64, users []*relation.UserCount, dateCount map[string]int64, err error) {
|
||||
return db.msgDocDatabase.RangeUserSendCount(ctx, start, end, group, ase, pageNumber, showNumber)
|
||||
}
|
||||
|
||||
@@ -1055,7 +1016,7 @@ func (db *commonMsgDatabase) RangeGroupSendCount(
|
||||
ase bool,
|
||||
pageNumber int32,
|
||||
showNumber int32,
|
||||
) (msgCount int64, userCount int64, groups []*unrelationtb.GroupCount, dateCount map[string]int64, err error) {
|
||||
) (msgCount int64, userCount int64, groups []*relation.GroupCount, dateCount map[string]int64, err error) {
|
||||
return db.msgDocDatabase.RangeGroupSendCount(ctx, start, end, ase, pageNumber, showNumber)
|
||||
}
|
||||
|
||||
@@ -1078,12 +1039,12 @@ func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationID
|
||||
totalMsgs := make(map[string]*sdkws.MsgData)
|
||||
for _, conversationID := range conversationIDs {
|
||||
seq := seqs[conversationID]
|
||||
docID := db.msg.GetDocID(conversationID, seq)
|
||||
docID := db.msgTable.GetDocID(conversationID, seq)
|
||||
msgs, err := db.msgDocDatabase.FindOneByDocID(ctx, docID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index := db.msg.GetMsgIndex(seq)
|
||||
index := db.msgTable.GetMsgIndex(seq)
|
||||
totalMsgs[conversationID] = convert.MsgDB2Pb(msgs.Msg[index].Msg)
|
||||
}
|
||||
return totalMsgs, nil
|
||||
@@ -1092,3 +1053,72 @@ func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationID
|
||||
func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
|
||||
db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) GetBeforeMsg(ctx context.Context, ts int64, limit int) ([]*relation.MsgDocModel, error) {
|
||||
return db.msgDocDatabase.GetBeforeMsg(ctx, ts, limit)
|
||||
}
|
||||
|
||||
func (db *commonMsgDatabase) DeleteDocMsgBefore(ctx context.Context, ts int64, doc *relation.MsgDocModel) ([]int, error) {
|
||||
var notNull int
|
||||
index := make([]int, 0, len(doc.Msg))
|
||||
for i, message := range doc.Msg {
|
||||
if message.Msg != nil {
|
||||
notNull++
|
||||
if message.Msg.SendTime < ts {
|
||||
index = append(index, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(index) == 0 {
|
||||
return index, nil
|
||||
}
|
||||
maxSeq := doc.Msg[index[len(index)-1]].Msg.Seq
|
||||
conversationID := doc.DocID[:strings.LastIndex(doc.DocID, ":")]
|
||||
if err := db.setMinSeq(ctx, conversationID, maxSeq+1); err != nil {
|
||||
return index, err
|
||||
}
|
||||
if len(index) == notNull {
|
||||
return index, db.msgDocDatabase.DeleteDoc(ctx, doc.DocID)
|
||||
} else {
|
||||
return index, db.msgDocDatabase.DeleteMsgByIndex(ctx, doc.DocID, index)
|
||||
}
|
||||
}
|
||||
|
||||
//func (db *commonMsgDatabase) ClearMsg(ctx context.Context, ts int64) (err error) {
|
||||
// var (
|
||||
// docNum int
|
||||
// msgNum int
|
||||
// start = time.Now()
|
||||
// )
|
||||
// for {
|
||||
// msgs, err := db.msgDocDatabase.GetBeforeMsg(ctx, ts, 100)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if len(msgs) == 0 {
|
||||
// return nil
|
||||
// }
|
||||
// for _, msg := range msgs {
|
||||
// num, err := db.deleteOneMsg(ctx, ts, msg)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// docNum++
|
||||
// msgNum += num
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
func (db *commonMsgDatabase) setMinSeq(ctx context.Context, conversationID string, seq int64) error {
|
||||
dbSeq, err := db.seq.GetMinSeq(ctx, conversationID)
|
||||
if err != nil {
|
||||
if errors.Is(errs.Unwrap(err), redis.Nil) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if dbSeq >= seq {
|
||||
return nil
|
||||
}
|
||||
return db.seq.SetMinSeq(ctx, conversationID, seq)
|
||||
}
|
||||
|
||||
@@ -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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
||||
)
|
||||
|
||||
func Test_BatchInsertChat2DB(t *testing.T) {
|
||||
conf := config.NewGlobalConfig()
|
||||
conf.Mongo.Address = []string{"192.168.44.128:37017"}
|
||||
// conf.Mongo.Timeout = 60
|
||||
conf.Mongo.Database = "openIM"
|
||||
// conf.Mongo.Source = "admin"
|
||||
conf.Mongo.Username = "root"
|
||||
conf.Mongo.Password = "openIM123"
|
||||
conf.Mongo.MaxPoolSize = 100
|
||||
conf.RetainChatRecords = 3650
|
||||
conf.ChatRecordsClearTime = "0 2 * * 3"
|
||||
|
||||
mongo, err := unrelation.NewMongo(conf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
db := &commonMsgDatabase{
|
||||
msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)),
|
||||
}
|
||||
|
||||
//ctx := context.Background()
|
||||
//msgs := make([]*sdkws.MsgData, 0, 1)
|
||||
//for i := 0; i < cap(msgs); i++ {
|
||||
// msgs = append(msgs, &sdkws.MsgData{
|
||||
// Content: []byte(fmt.Sprintf("test-%d", i)),
|
||||
// SendTime: time.Now().UnixMilli(),
|
||||
// })
|
||||
//}
|
||||
//err = db.BatchInsertChat2DB(ctx, "test", msgs, 0)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
|
||||
_ = db.BatchInsertChat2DB
|
||||
c := mongo.GetDatabase(conf.Mongo.Database).Collection("msg")
|
||||
|
||||
ch := make(chan int)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
index := 10
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func(channelID int) {
|
||||
defer wg.Done()
|
||||
<-ch
|
||||
var arr []string
|
||||
for i := 0; i < 500; i++ {
|
||||
arr = append(arr, strconv.Itoa(i+1))
|
||||
}
|
||||
rand.Shuffle(len(arr), func(i, j int) {
|
||||
arr[i], arr[j] = arr[j], arr[i]
|
||||
})
|
||||
for j, s := range arr {
|
||||
if j == 0 {
|
||||
fmt.Printf("channnelID: %d, arr[0]: %s\n", channelID, arr[j])
|
||||
}
|
||||
filter := bson.M{"doc_id": "test:0"}
|
||||
update := bson.M{
|
||||
"$addToSet": bson.M{
|
||||
fmt.Sprintf("msgs.%d.del_list", index): bson.M{"$each": []string{s}},
|
||||
},
|
||||
}
|
||||
_, err := c.UpdateOne(context.Background(), filter, update)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-ch
|
||||
var arr []string
|
||||
for i := 0; i < 500; i++ {
|
||||
arr = append(arr, strconv.Itoa(1001+i))
|
||||
}
|
||||
rand.Shuffle(len(arr), func(i, j int) {
|
||||
arr[i], arr[j] = arr[j], arr[i]
|
||||
})
|
||||
for _, s := range arr {
|
||||
filter := bson.M{"doc_id": "test:0"}
|
||||
update := bson.M{
|
||||
"$addToSet": bson.M{
|
||||
fmt.Sprintf("msgs.%d.read_list", index): bson.M{"$each": []string{s}},
|
||||
},
|
||||
}
|
||||
_, err := c.UpdateOne(context.Background(), filter, update)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
close(ch)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
}
|
||||
|
||||
func GetDB() *commonMsgDatabase {
|
||||
conf := config.NewGlobalConfig()
|
||||
conf.Mongo.Address = []string{"203.56.175.233:37017"}
|
||||
// conf.Mongo.Timeout = 60
|
||||
conf.Mongo.Database = "openim_v3"
|
||||
// conf.Mongo.Source = "admin"
|
||||
conf.Mongo.Username = "root"
|
||||
conf.Mongo.Password = "openIM123"
|
||||
conf.Mongo.MaxPoolSize = 100
|
||||
conf.RetainChatRecords = 3650
|
||||
conf.ChatRecordsClearTime = "0 2 * * 3"
|
||||
|
||||
mongo, err := unrelation.NewMongo(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = mongo.GetDatabase(conf.Mongo.Database).Client().Ping(context.Background(), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &commonMsgDatabase{
|
||||
msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase(conf.Mongo.Database)),
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Insert(t *testing.T) {
|
||||
db := GetDB()
|
||||
ctx := context.Background()
|
||||
var arr []any
|
||||
for i := 0; i < 345; i++ {
|
||||
if i%2 == 0 {
|
||||
arr = append(arr, (*unrelationtb.MsgDataModel)(nil))
|
||||
continue
|
||||
}
|
||||
arr = append(arr, &unrelationtb.MsgDataModel{
|
||||
Seq: int64(i),
|
||||
Content: fmt.Sprintf("test-%d", i),
|
||||
})
|
||||
}
|
||||
if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyMsg, 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Revoke(t *testing.T) {
|
||||
db := GetDB()
|
||||
ctx := context.Background()
|
||||
var arr []any
|
||||
for i := 0; i < 456; i++ {
|
||||
arr = append(arr, &unrelationtb.RevokeModel{
|
||||
UserID: "uid_" + strconv.Itoa(i),
|
||||
Nickname: "uname_" + strconv.Itoa(i),
|
||||
Time: time.Now().UnixMilli(),
|
||||
})
|
||||
}
|
||||
if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyRevoke, 123); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FindBySeq(t *testing.T) {
|
||||
if err := log.InitFromConfig("", "", 6, true, false, "", 2, 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
db := GetDB()
|
||||
ctx := context.Background()
|
||||
fmt.Println(
|
||||
db.msgDocDatabase.(*unrelation.MsgMongoDriver).GetMsgBySeqIndexIn1Doc(ctx, "100", "si_100_101:0", []int64{1}),
|
||||
)
|
||||
//res, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, "123456", "test:0", []int64{1, 2, 3})
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//db.GetMsgBySeqs(ctx, "100", "si_100_101:0", []int64{6})
|
||||
//data, _ := json.Marshal(res)
|
||||
//fmt.Println(string(data))
|
||||
}
|
||||
|
||||
//func Test_Delete(t *testing.T) {
|
||||
// db := GetDB()
|
||||
// ctx := context.Background()
|
||||
// var arr []any
|
||||
// for i := 0; i < 123; i++ {
|
||||
// arr = append(arr, []string{"uid_1", "uid_2"})
|
||||
// }
|
||||
// if err := db.BatchInsertBlock(ctx, "test", arr, updateKeyDel, 210); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
//}
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
db := GetDB()
|
||||
var seqs []int64
|
||||
for i := int64(1); i <= 50; i++ {
|
||||
seqs = append(seqs, i)
|
||||
}
|
||||
msgs, err := db.getMsgBySeqsRange(context.Background(), "4931176757", "si_3866692501_4931176757", seqs, seqs[0], seqs[len(seqs)-1])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(msgs)
|
||||
|
||||
}
|
||||
@@ -25,10 +25,10 @@ type PushDatabase interface {
|
||||
}
|
||||
|
||||
type pushDataBase struct {
|
||||
cache cache.MsgModel
|
||||
cache cache.ThirdCache
|
||||
}
|
||||
|
||||
func NewPushDatabase(cache cache.MsgModel) PushDatabase {
|
||||
func NewPushDatabase(cache cache.ThirdCache) PushDatabase {
|
||||
return &pushDataBase{cache: cache}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/s3"
|
||||
"github.com/openimsdk/tools/s3/cont"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
)
|
||||
|
||||
type ThirdDatabase interface {
|
||||
@@ -34,7 +34,7 @@ type ThirdDatabase interface {
|
||||
}
|
||||
|
||||
type thirdDatabase struct {
|
||||
cache cache.MsgModel
|
||||
cache cache.ThirdCache
|
||||
logdb relation.LogInterface
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (t *thirdDatabase) UploadLogs(ctx context.Context, logs []*relation.LogMode
|
||||
return t.logdb.Create(ctx, logs)
|
||||
}
|
||||
|
||||
func NewThirdDatabase(cache cache.MsgModel, logdb relation.LogInterface) ThirdDatabase {
|
||||
func NewThirdDatabase(cache cache.ThirdCache, logdb relation.LogInterface) ThirdDatabase {
|
||||
return &thirdDatabase{cache: cache, logdb: logdb}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,16 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/db/tx"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/user"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/OpenIMSDK/tools/tx"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/protocol/user"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"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"
|
||||
)
|
||||
|
||||
type UserDatabase interface {
|
||||
@@ -39,13 +39,11 @@ type UserDatabase interface {
|
||||
FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error)
|
||||
// Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db
|
||||
Create(ctx context.Context, users []*relation.UserModel) (err error)
|
||||
// Update update (non-zero value) external guarantee userID exists
|
||||
//Update(ctx context.Context, user *relation.UserModel) (err error)
|
||||
// UpdateByMap update (zero value) external guarantee userID exists
|
||||
UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error)
|
||||
// FindUser
|
||||
PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error)
|
||||
//FindUser with keyword
|
||||
// FindUser with keyword
|
||||
PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID string, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error)
|
||||
// Page If not found, no error is returned
|
||||
Page(ctx context.Context, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error)
|
||||
@@ -74,7 +72,7 @@ type UserDatabase interface {
|
||||
// SetUserStatus Set the user status and store the user status in redis
|
||||
SetUserStatus(ctx context.Context, userID string, status, platformID int32) error
|
||||
|
||||
//CRUD user command
|
||||
// CRUD user command
|
||||
AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error
|
||||
DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error
|
||||
UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error
|
||||
@@ -83,19 +81,19 @@ type UserDatabase interface {
|
||||
}
|
||||
|
||||
type userDatabase struct {
|
||||
tx tx.CtxTx
|
||||
tx tx.Tx
|
||||
userDB relation.UserModelInterface
|
||||
cache cache.UserCache
|
||||
mongoDB unrelationtb.UserModelInterface
|
||||
mongoDB relation.SubscribeUserModelInterface
|
||||
}
|
||||
|
||||
func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.CtxTx, mongoDB unrelationtb.UserModelInterface) UserDatabase {
|
||||
func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx, mongoDB relation.SubscribeUserModelInterface) UserDatabase {
|
||||
return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB}
|
||||
}
|
||||
|
||||
func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) error {
|
||||
// Extract user IDs from the given user models.
|
||||
userIDs := utils.Slice(users, func(e *relation.UserModel) string {
|
||||
userIDs := datautil.Slice(users, func(e *relation.UserModel) string {
|
||||
return e.UserID
|
||||
})
|
||||
|
||||
@@ -106,7 +104,7 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel
|
||||
}
|
||||
|
||||
// Determine which users are missing from the database.
|
||||
missingUsers := utils.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string {
|
||||
missingUsers := datautil.SliceAnySub(users, existingUsers, func(e *relation.UserModel) string {
|
||||
return e.UserID
|
||||
})
|
||||
|
||||
@@ -127,7 +125,7 @@ func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (use
|
||||
return
|
||||
}
|
||||
if len(users) != len(userIDs) {
|
||||
err = errs.ErrRecordNotFound.Wrap("userID not found")
|
||||
err = errs.ErrRecordNotFound.WrapMsg("userID not found")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -137,12 +135,10 @@ func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*rel
|
||||
return u.cache.GetUsersInfo(ctx, userIDs)
|
||||
}
|
||||
|
||||
// Find userInfo By Nickname.
|
||||
func (u *userDatabase) FindByNickname(ctx context.Context, nickname string) (users []*relation.UserModel, err error) {
|
||||
return u.userDB.TakeByNickname(ctx, nickname)
|
||||
}
|
||||
|
||||
// Find notificationAccouts.
|
||||
func (u *userDatabase) FindNotification(ctx context.Context, level int64) (users []*relation.UserModel, err error) {
|
||||
return u.userDB.TakeNotification(ctx, level)
|
||||
}
|
||||
@@ -153,20 +149,12 @@ func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel)
|
||||
if err = u.userDB.Create(ctx, users); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.cache.DelUsersInfo(utils.Slice(users, func(e *relation.UserModel) string {
|
||||
return u.cache.DelUsersInfo(datautil.Slice(users, func(e *relation.UserModel) string {
|
||||
return e.UserID
|
||||
})...).ExecDel(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
//// Update (non-zero value) externally guarantees that userID exists.
|
||||
//func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) {
|
||||
// if err := u.userDB.Update(ctx, user); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx)
|
||||
//}
|
||||
|
||||
// UpdateByMap update (zero value) externally guarantees that userID exists.
|
||||
func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]any) (err error) {
|
||||
return u.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
@@ -186,13 +174,7 @@ func (u *userDatabase) PageFindUser(ctx context.Context, level1 int64, level2 in
|
||||
return u.userDB.PageFindUser(ctx, level1, level2, pagination)
|
||||
}
|
||||
|
||||
func (u *userDatabase) PageFindUserWithKeyword(
|
||||
ctx context.Context,
|
||||
level1 int64,
|
||||
level2 int64,
|
||||
userID, nickName string,
|
||||
pagination pagination.Pagination,
|
||||
) (count int64, users []*relation.UserModel, err error) {
|
||||
func (u *userDatabase) PageFindUserWithKeyword(ctx context.Context, level1 int64, level2 int64, userID, nickName string, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) {
|
||||
return u.userDB.PageFindUserWithKeyword(ctx, level1, level2, userID, nickName, pagination)
|
||||
}
|
||||
|
||||
@@ -267,19 +249,24 @@ func (u *userDatabase) GetUserStatus(ctx context.Context, userIDs []string) ([]*
|
||||
func (u *userDatabase) SetUserStatus(ctx context.Context, userID string, status, platformID int32) error {
|
||||
return u.cache.SetUserStatus(ctx, userID, status, platformID)
|
||||
}
|
||||
|
||||
func (u *userDatabase) AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error {
|
||||
return u.userDB.AddUserCommand(ctx, userID, Type, UUID, value, ex)
|
||||
}
|
||||
|
||||
func (u *userDatabase) DeleteUserCommand(ctx context.Context, userID string, Type int32, UUID string) error {
|
||||
return u.userDB.DeleteUserCommand(ctx, userID, Type, UUID)
|
||||
}
|
||||
|
||||
func (u *userDatabase) UpdateUserCommand(ctx context.Context, userID string, Type int32, UUID string, val map[string]any) error {
|
||||
return u.userDB.UpdateUserCommand(ctx, userID, Type, UUID, val)
|
||||
}
|
||||
|
||||
func (u *userDatabase) GetUserCommands(ctx context.Context, userID string, Type int32) ([]*user.CommandInfoResp, error) {
|
||||
commands, err := u.userDB.GetUserCommand(ctx, userID, Type)
|
||||
return commands, err
|
||||
}
|
||||
|
||||
func (u *userDatabase) GetAllUserCommands(ctx context.Context, userID string) ([]*user.AllCommandInfoResp, error) {
|
||||
commands, err := u.userDB.GetAllUserCommand(ctx, userID)
|
||||
return commands, err
|
||||
|
||||
+11
-11
@@ -17,9 +17,9 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -63,42 +63,42 @@ func (b *BlackMgo) blacksFilter(blacks []*relation.BlackModel) bson.M {
|
||||
}
|
||||
|
||||
func (b *BlackMgo) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) {
|
||||
return mgoutil.InsertMany(ctx, b.coll, blacks)
|
||||
return mongoutil.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))
|
||||
return mongoutil.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)
|
||||
return mongoutil.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))
|
||||
return mongoutil.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))
|
||||
return mongoutil.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)
|
||||
return mongoutil.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 mongoutil.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}})
|
||||
return mongoutil.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}))
|
||||
return mongoutil.Find[string](ctx, b.coll, bson.M{"owner_user_id": ownerUserID}, options.Find().SetProjection(bson.M{"_id": 0, "block_user_id": 1}))
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -48,15 +48,24 @@ type ConversationMgo struct {
|
||||
}
|
||||
|
||||
func (c *ConversationMgo) Create(ctx context.Context, conversations []*relation.ConversationModel) (err error) {
|
||||
return mgoutil.InsertMany(ctx, c.coll, conversations)
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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 len(args) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
filter := bson.M{
|
||||
"conversation_id": conversationID,
|
||||
}
|
||||
if len(userIDs) > 0 {
|
||||
filter["owner_user_id"] = bson.M{"$in": userIDs}
|
||||
}
|
||||
res, err := mongoutil.UpdateMany(ctx, c.coll, filter, bson.M{"$set": args})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -64,36 +73,35 @@ func (c *ConversationMgo) UpdateByMap(ctx context.Context, userIDs []string, con
|
||||
}
|
||||
|
||||
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)
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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](
|
||||
return mongoutil.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}))
|
||||
return mongoutil.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})
|
||||
return mongoutil.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}))
|
||||
return mongoutil.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})
|
||||
return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID})
|
||||
}
|
||||
|
||||
func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) {
|
||||
@@ -103,22 +111,22 @@ func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID
|
||||
} else {
|
||||
filter = bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$in": recvOpts}}
|
||||
}
|
||||
return mgoutil.Find[string](ctx, c.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}))
|
||||
return mongoutil.Find[string](ctx, c.coll, filter, 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}))
|
||||
return mongoutil.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{
|
||||
return mongoutil.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{
|
||||
counts, err := mongoutil.Aggregate[int64](ctx, c.coll, []bson.M{
|
||||
{"$group": bson.M{"_id": "$conversation_id"}},
|
||||
{"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}},
|
||||
{"$project": bson.M{"_id": 0}},
|
||||
@@ -133,16 +141,16 @@ func (c *ConversationMgo) GetAllConversationIDsNumber(ctx context.Context) (int6
|
||||
}
|
||||
|
||||
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}))
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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 != 0 && (UNIX_TIMESTAMP(NOW()) > (msg_destruct_time + UNIX_TIMESTAMP(latest_msg_destruct_time)) || latest_msg_destruct_time is NULL)"
|
||||
return mongoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{
|
||||
"is_msg_destruct": 1,
|
||||
"msg_destruct_time": bson.M{"$ne": 0},
|
||||
"$or": []bson.M{
|
||||
@@ -162,7 +170,7 @@ func (c *ConversationMgo) GetConversationIDsNeedDestruct(ctx context.Context) ([
|
||||
}
|
||||
|
||||
func (c *ConversationMgo) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
|
||||
return mgoutil.Find[string](
|
||||
return mongoutil.Find[string](
|
||||
ctx,
|
||||
c.coll,
|
||||
bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$ne": constant.ReceiveMessage}},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
// Copyright © 2024 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.
|
||||
@@ -12,4 +12,4 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package http // import "github.com/openimsdk/open-im-server/v3/pkg/common/http"
|
||||
package mgo // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
|
||||
+13
-13
@@ -17,9 +17,9 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -48,7 +48,7 @@ func NewFriendMongo(db *mongo.Database) (relation.FriendModelInterface, error) {
|
||||
|
||||
// Create inserts multiple friend records.
|
||||
func (f *FriendMgo) Create(ctx context.Context, friends []*relation.FriendModel) error {
|
||||
return mgoutil.InsertMany(ctx, f.coll, friends)
|
||||
return mongoutil.InsertMany(ctx, f.coll, friends)
|
||||
}
|
||||
|
||||
// Delete removes specified friends of the owner user.
|
||||
@@ -57,7 +57,7 @@ func (f *FriendMgo) Delete(ctx context.Context, ownerUserID string, friendUserID
|
||||
"owner_user_id": ownerUserID,
|
||||
"friend_user_id": bson.M{"$in": friendUserIDs},
|
||||
}
|
||||
return mgoutil.DeleteOne(ctx, f.coll, filter)
|
||||
return mongoutil.DeleteOne(ctx, f.coll, filter)
|
||||
}
|
||||
|
||||
// UpdateByMap updates specific fields of a friend document using a map.
|
||||
@@ -69,7 +69,7 @@ func (f *FriendMgo) UpdateByMap(ctx context.Context, ownerUserID string, friendU
|
||||
"owner_user_id": ownerUserID,
|
||||
"friend_user_id": friendUserID,
|
||||
}
|
||||
return mgoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true)
|
||||
return mongoutil.UpdateOne(ctx, f.coll, filter, bson.M{"$set": args}, true)
|
||||
}
|
||||
|
||||
// Update modifies multiple friend documents.
|
||||
@@ -92,7 +92,7 @@ func (f *FriendMgo) Take(ctx context.Context, ownerUserID, friendUserID string)
|
||||
"owner_user_id": ownerUserID,
|
||||
"friend_user_id": friendUserID,
|
||||
}
|
||||
return mgoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter)
|
||||
return mongoutil.FindOne[*relation.FriendModel](ctx, f.coll, filter)
|
||||
}
|
||||
|
||||
// FindUserState finds the friendship status between two users.
|
||||
@@ -103,7 +103,7 @@ func (f *FriendMgo) FindUserState(ctx context.Context, userID1, userID2 string)
|
||||
{"owner_user_id": userID2, "friend_user_id": userID1},
|
||||
},
|
||||
}
|
||||
return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
|
||||
return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
|
||||
}
|
||||
|
||||
// FindFriends retrieves a list of friends for a given owner. Missing friends do not cause an error.
|
||||
@@ -112,7 +112,7 @@ func (f *FriendMgo) FindFriends(ctx context.Context, ownerUserID string, friendU
|
||||
"owner_user_id": ownerUserID,
|
||||
"friend_user_id": bson.M{"$in": friendUserIDs},
|
||||
}
|
||||
return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
|
||||
return mongoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
|
||||
}
|
||||
|
||||
// FindReversalFriends finds users who have added the specified user as a friend.
|
||||
@@ -121,25 +121,25 @@ func (f *FriendMgo) FindReversalFriends(ctx context.Context, friendUserID string
|
||||
"owner_user_id": bson.M{"$in": ownerUserIDs},
|
||||
"friend_user_id": friendUserID,
|
||||
}
|
||||
return mgoutil.Find[*relation.FriendModel](ctx, f.coll, filter)
|
||||
return mongoutil.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)
|
||||
return mongoutil.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)
|
||||
return mongoutil.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}))
|
||||
return mongoutil.Find[string](ctx, f.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "friend_user_id": 1}))
|
||||
}
|
||||
|
||||
func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, val map[string]any) error {
|
||||
@@ -158,6 +158,6 @@ func (f *FriendMgo) UpdateFriends(ctx context.Context, ownerUserID string, frien
|
||||
update := bson.M{"$set": val}
|
||||
|
||||
// Perform the update operation for all matching documents
|
||||
_, err := mgoutil.UpdateMany(ctx, f.coll, filter, update)
|
||||
_, err := mongoutil.UpdateMany(ctx, f.coll, filter, update)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -45,11 +45,11 @@ type FriendRequestMgo struct {
|
||||
}
|
||||
|
||||
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)
|
||||
return mongoutil.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)
|
||||
return mongoutil.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) {
|
||||
@@ -57,22 +57,22 @@ func (f *FriendRequestMgo) FindBothFriendRequests(ctx context.Context, fromUserI
|
||||
{"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)
|
||||
return mongoutil.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)
|
||||
return mongoutil.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})
|
||||
return mongoutil.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)
|
||||
return mongoutil.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) {
|
||||
@@ -99,11 +99,11 @@ func (f *FriendRequestMgo) Update(ctx context.Context, friendRequest *relation.F
|
||||
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)
|
||||
return mongoutil.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})
|
||||
return mongoutil.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) {
|
||||
|
||||
+14
-12
@@ -18,11 +18,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -47,7 +47,7 @@ type GroupMgo struct {
|
||||
}
|
||||
|
||||
func (g *GroupMgo) Create(ctx context.Context, groups []*relation.GroupModel) (err error) {
|
||||
return mgoutil.InsertMany(ctx, g.coll, groups)
|
||||
return mongoutil.InsertMany(ctx, g.coll, groups)
|
||||
}
|
||||
|
||||
func (g *GroupMgo) UpdateStatus(ctx context.Context, groupID string, status int32) (err error) {
|
||||
@@ -58,21 +58,23 @@ func (g *GroupMgo) UpdateMap(ctx context.Context, groupID string, args map[strin
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID}, bson.M{"$set": args}, true)
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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})
|
||||
return mongoutil.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) {
|
||||
// Define the sorting options
|
||||
opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}})
|
||||
|
||||
return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{
|
||||
// Perform the search with pagination and sorting
|
||||
return mongoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{
|
||||
"group_name": bson.M{"$regex": keyword},
|
||||
"status": bson.M{"$ne": constant.GroupStatusDismissed},
|
||||
}, pagination, opts)
|
||||
@@ -80,9 +82,9 @@ func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagina
|
||||
|
||||
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 mongoutil.Count(ctx, g.coll, bson.M{})
|
||||
}
|
||||
return mgoutil.Count(ctx, g.coll, bson.M{"create_time": bson.M{"$lt": before}})
|
||||
return mongoutil.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) {
|
||||
@@ -113,7 +115,7 @@ func (g *GroupMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time,
|
||||
Date string `bson:"_id"`
|
||||
Count int64 `bson:"count"`
|
||||
}
|
||||
items, err := mgoutil.Aggregate[Item](ctx, g.coll, pipeline)
|
||||
items, err := mongoutil.Aggregate[Item](ctx, g.coll, pipeline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -47,7 +47,7 @@ type GroupMemberMgo struct {
|
||||
}
|
||||
|
||||
func (g *GroupMemberMgo) Create(ctx context.Context, groupMembers []*relation.GroupMemberModel) (err error) {
|
||||
return mgoutil.InsertMany(ctx, g.coll, groupMembers)
|
||||
return mongoutil.InsertMany(ctx, g.coll, groupMembers)
|
||||
}
|
||||
|
||||
func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []string) (err error) {
|
||||
@@ -55,7 +55,7 @@ func (g *GroupMemberMgo) Delete(ctx context.Context, groupID string, userIDs []s
|
||||
if len(userIDs) > 0 {
|
||||
filter["user_id"] = bson.M{"$in": userIDs}
|
||||
}
|
||||
return mgoutil.DeleteMany(ctx, g.coll, filter)
|
||||
return mongoutil.DeleteMany(ctx, g.coll, filter)
|
||||
}
|
||||
|
||||
func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, userID string, roleLevel int32) error {
|
||||
@@ -63,41 +63,41 @@ func (g *GroupMemberMgo) UpdateRoleLevel(ctx context.Context, groupID string, us
|
||||
}
|
||||
|
||||
func (g *GroupMemberMgo) Update(ctx context.Context, groupID string, userID string, data map[string]any) (err error) {
|
||||
return mgoutil.UpdateOne(ctx, g.coll, bson.M{"group_id": groupID, "user_id": userID}, bson.M{"$set": data}, true)
|
||||
return mongoutil.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
|
||||
// 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}))
|
||||
return mongoutil.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})
|
||||
return mongoutil.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})
|
||||
return mongoutil.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}))
|
||||
return mongoutil.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) {
|
||||
filter := bson.M{"group_id": groupID, "nickname": bson.M{"$regex": keyword}}
|
||||
return mgoutil.FindPage[*relation.GroupMemberModel](ctx, g.coll, filter, pagination)
|
||||
return mongoutil.FindPage[*relation.GroupMemberModel](ctx, g.coll, filter, pagination)
|
||||
}
|
||||
|
||||
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}))
|
||||
return mongoutil.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})
|
||||
return mongoutil.Count(ctx, g.coll, bson.M{"group_id": groupID})
|
||||
}
|
||||
|
||||
func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
|
||||
@@ -107,7 +107,7 @@ func (g *GroupMemberMgo) FindUserManagedGroupID(ctx context.Context, userID stri
|
||||
"$in": []int{constant.GroupOwner, constant.GroupAdmin},
|
||||
},
|
||||
}
|
||||
return mgoutil.Find[string](ctx, g.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "group_id": 1}))
|
||||
return mongoutil.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 {
|
||||
|
||||
@@ -17,10 +17,10 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -46,29 +46,29 @@ type GroupRequestMgo struct {
|
||||
}
|
||||
|
||||
func (g *GroupRequestMgo) Create(ctx context.Context, groupRequests []*relation.GroupRequestModel) (err error) {
|
||||
return mgoutil.InsertMany(ctx, g.coll, groupRequests)
|
||||
return mongoutil.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})
|
||||
return mongoutil.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)
|
||||
return mongoutil.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})
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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)
|
||||
return mongoutil.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)
|
||||
return mongoutil.FindPage[*relation.GroupRequestModel](ctx, g.coll, bson.M{"group_id": bson.M{"$in": groupIDs}}, pagination)
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -57,7 +57,7 @@ type LogMgo struct {
|
||||
}
|
||||
|
||||
func (l *LogMgo) Create(ctx context.Context, log []*relation.LogModel) error {
|
||||
return mgoutil.InsertMany(ctx, l.coll, log)
|
||||
return mongoutil.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) {
|
||||
@@ -65,19 +65,19 @@ func (l *LogMgo) Search(ctx context.Context, keyword string, start time.Time, en
|
||||
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}))
|
||||
return mongoutil.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 mongoutil.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})
|
||||
return mongoutil.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 mongoutil.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})
|
||||
return mongoutil.Find[*relation.LogModel](ctx, l.coll, bson.M{"log_id": bson.M{"$in": logIDs}, "user_id": userID})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,9 @@ package mgo
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -54,16 +54,16 @@ func (o *S3Mongo) SetObject(ctx context.Context, obj *relation.ObjectModel) erro
|
||||
"group": obj.Group,
|
||||
"create_time": obj.CreateTime,
|
||||
}
|
||||
return mgoutil.UpdateOne(ctx, o.coll, filter, bson.M{"$set": update}, false, options.Update().SetUpsert(true))
|
||||
return mongoutil.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 mongoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name})
|
||||
}
|
||||
return mgoutil.FindOne[*relation.ObjectModel](ctx, o.coll, bson.M{"name": name, "engine": engine})
|
||||
return mongoutil.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})
|
||||
return mongoutil.DeleteOne(ctx, o.coll, bson.M{"name": name, "engine": engine})
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unrelation
|
||||
package mgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
@@ -35,9 +35,9 @@ const (
|
||||
MaximumSubscription = 3000
|
||||
)
|
||||
|
||||
func NewUserMongoDriver(database *mongo.Database) unrelation.UserModelInterface {
|
||||
func NewUserMongoDriver(database *mongo.Database) relation.SubscribeUserModelInterface {
|
||||
return &UserMongoDriver{
|
||||
userCollection: database.Collection(unrelation.SubscribeUser),
|
||||
userCollection: database.Collection(relation.SubscribeUser),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string
|
||||
opts,
|
||||
)
|
||||
if err != nil {
|
||||
return errs.Wrap(err, "transaction failed")
|
||||
return errs.WrapMsg(err, "transaction failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -155,7 +155,7 @@ func (u *UserMongoDriver) RemoveSubscribedListFromUser(ctx context.Context, user
|
||||
|
||||
// GetAllSubscribeList Get all users subscribed by this user.
|
||||
func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string) (userIDList []string, err error) {
|
||||
var user unrelation.UserModel
|
||||
var user relation.SubscribeUserModel
|
||||
cursor := u.userCollection.FindOne(
|
||||
ctx,
|
||||
bson.M{"user_id": SubscriptionPrefix + userID})
|
||||
@@ -172,7 +172,7 @@ func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string
|
||||
|
||||
// GetSubscribedList Get the user subscribed by those users.
|
||||
func (u *UserMongoDriver) GetSubscribedList(ctx context.Context, userID string) (userIDList []string, err error) {
|
||||
var user unrelation.UserModel
|
||||
var user relation.SubscribeUserModel
|
||||
cursor := u.userCollection.FindOne(
|
||||
ctx,
|
||||
bson.M{"user_id": SubscribedPrefix + userID})
|
||||
+19
-19
@@ -18,11 +18,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/user"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||
"github.com/openimsdk/protocol/user"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/db/pagination"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
@@ -48,34 +48,34 @@ type UserMgo struct {
|
||||
}
|
||||
|
||||
func (u *UserMgo) Create(ctx context.Context, users []*relation.UserModel) error {
|
||||
return mgoutil.InsertMany(ctx, u.coll, users)
|
||||
return mongoutil.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)
|
||||
return mongoutil.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}})
|
||||
return mongoutil.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})
|
||||
return mongoutil.FindOne[*relation.UserModel](ctx, u.coll, bson.M{"user_id": userID})
|
||||
}
|
||||
|
||||
func (u *UserMgo) TakeNotification(ctx context.Context, level int64) (user []*relation.UserModel, err error) {
|
||||
return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"app_manger_level": level})
|
||||
return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"app_manger_level": level})
|
||||
}
|
||||
|
||||
func (u *UserMgo) TakeByNickname(ctx context.Context, nickname string) (user []*relation.UserModel, err error) {
|
||||
return mgoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"nickname": nickname})
|
||||
return mongoutil.Find[*relation.UserModel](ctx, u.coll, bson.M{"nickname": nickname})
|
||||
}
|
||||
|
||||
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)
|
||||
return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, bson.M{}, pagination)
|
||||
}
|
||||
|
||||
func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64, pagination pagination.Pagination) (count int64, users []*relation.UserModel, err error) {
|
||||
@@ -86,7 +86,7 @@ func (u *UserMgo) PageFindUser(ctx context.Context, level1 int64, level2 int64,
|
||||
},
|
||||
}
|
||||
|
||||
return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination)
|
||||
return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination)
|
||||
}
|
||||
|
||||
func (u *UserMgo) PageFindUserWithKeyword(
|
||||
@@ -121,26 +121,26 @@ func (u *UserMgo) PageFindUserWithKeyword(
|
||||
}
|
||||
|
||||
// Perform the paginated search
|
||||
return mgoutil.FindPage[*relation.UserModel](ctx, u.coll, query, pagination)
|
||||
return mongoutil.FindPage[*relation.UserModel](ctx, u.coll, query, 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{"_id": 0, "user_id": 1}))
|
||||
return mongoutil.FindPage[string](ctx, u.coll, bson.M{}, pagination, options.Find().SetProjection(bson.M{"_id": 0, "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})
|
||||
return mongoutil.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{"_id": 0, "global_recv_msg_opt": 1}))
|
||||
return mongoutil.FindOne[int](ctx, u.coll, bson.M{"user_id": userID}, options.FindOne().SetProjection(bson.M{"_id": 0, "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 mongoutil.Count(ctx, u.coll, bson.M{})
|
||||
}
|
||||
return mgoutil.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}})
|
||||
return mongoutil.Count(ctx, u.coll, bson.M{"create_time": bson.M{"$lt": before}})
|
||||
}
|
||||
|
||||
func (u *UserMgo) AddUserCommand(ctx context.Context, userID string, Type int32, UUID string, value string, ex string) error {
|
||||
@@ -308,7 +308,7 @@ func (u *UserMgo) CountRangeEverydayTotal(ctx context.Context, start time.Time,
|
||||
Date string `bson:"_id"`
|
||||
Count int64 `bson:"count"`
|
||||
}
|
||||
items, err := mgoutil.Aggregate[Item](ctx, u.coll, pipeline)
|
||||
items, err := mongoutil.Aggregate[Item](ctx, u.coll, pipeline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright © 2023 OpenIM. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cont
|
||||
|
||||
const (
|
||||
// hashPath defines the storage path for hash data within the 'openim' directory.
|
||||
hashPath = "openim/data/hash/"
|
||||
|
||||
// tempPath specifies the directory for temporary files in the 'openim' structure.
|
||||
tempPath = "openim/temp/"
|
||||
|
||||
// DirectPath indicates the directory for direct uploads or access within the 'openim' structure.
|
||||
DirectPath = "openim/direct"
|
||||
|
||||
// UploadTypeMultipart represents the identifier for multipart uploads,
|
||||
// allowing large files to be uploaded in chunks.
|
||||
UploadTypeMultipart = 1
|
||||
|
||||
// UploadTypePresigned signifies the use of presigned URLs for uploads,
|
||||
// facilitating secure, authorized file transfers without requiring direct access to the storage credentials.
|
||||
UploadTypePresigned = 2
|
||||
|
||||
// partSeparator is used as a delimiter in multipart upload processes,
|
||||
// separating individual file parts.
|
||||
partSeparator = ","
|
||||
)
|
||||
@@ -1,282 +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 cont
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
)
|
||||
|
||||
func New(cache cache.S3Cache, impl s3.Interface) *Controller {
|
||||
return &Controller{
|
||||
cache: cache,
|
||||
impl: impl,
|
||||
}
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
cache cache.S3Cache
|
||||
impl s3.Interface
|
||||
}
|
||||
|
||||
func (c *Controller) Engine() string {
|
||||
return c.impl.Engine()
|
||||
}
|
||||
|
||||
func (c *Controller) HashPath(md5 string) string {
|
||||
return path.Join(hashPath, md5)
|
||||
}
|
||||
|
||||
func (c *Controller) NowPath() string {
|
||||
now := time.Now()
|
||||
return path.Join(
|
||||
fmt.Sprintf("%04d", now.Year()),
|
||||
fmt.Sprintf("%02d", now.Month()),
|
||||
fmt.Sprintf("%02d", now.Day()),
|
||||
fmt.Sprintf("%02d", now.Hour()),
|
||||
fmt.Sprintf("%02d", now.Minute()),
|
||||
fmt.Sprintf("%02d", now.Second()),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Controller) UUID() string {
|
||||
id := uuid.New()
|
||||
return hex.EncodeToString(id[:])
|
||||
}
|
||||
|
||||
func (c *Controller) PartSize(ctx context.Context, size int64) (int64, error) {
|
||||
return c.impl.PartSize(ctx, size)
|
||||
}
|
||||
|
||||
func (c *Controller) PartLimit() *s3.PartLimit {
|
||||
return c.impl.PartLimit()
|
||||
}
|
||||
|
||||
func (c *Controller) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) {
|
||||
return c.cache.GetKey(ctx, c.impl.Engine(), name)
|
||||
}
|
||||
|
||||
func (c *Controller) GetHashObject(ctx context.Context, hash string) (*s3.ObjectInfo, error) {
|
||||
return c.StatObject(ctx, c.HashPath(hash))
|
||||
}
|
||||
|
||||
func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*InitiateUploadResult, error) {
|
||||
defer log.ZDebug(ctx, "return")
|
||||
if size < 0 {
|
||||
return nil, errors.New("invalid size")
|
||||
}
|
||||
if hashBytes, err := hex.DecodeString(hash); err != nil {
|
||||
return nil, err
|
||||
} else if len(hashBytes) != md5.Size {
|
||||
return nil, errors.New("invalid md5")
|
||||
}
|
||||
partSize, err := c.impl.PartSize(ctx, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
partNumber := int(size / partSize)
|
||||
if size%partSize > 0 {
|
||||
partNumber++
|
||||
}
|
||||
if maxParts > 0 && partNumber > 0 && partNumber < maxParts {
|
||||
return nil, fmt.Errorf("too many parts: %d", partNumber)
|
||||
}
|
||||
if info, err := c.StatObject(ctx, c.HashPath(hash)); err == nil {
|
||||
return nil, &HashAlreadyExistsError{Object: info}
|
||||
} else if !c.impl.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
if size <= partSize {
|
||||
// Pre-signed upload
|
||||
key := path.Join(tempPath, c.NowPath(), fmt.Sprintf("%s_%d_%s.presigned", hash, size, c.UUID()))
|
||||
rawURL, err := c.impl.PresignedPutObject(ctx, key, expire)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &InitiateUploadResult{
|
||||
UploadID: newMultipartUploadID(multipartUploadID{
|
||||
Type: UploadTypePresigned,
|
||||
ID: "",
|
||||
Key: key,
|
||||
Size: size,
|
||||
Hash: hash,
|
||||
}),
|
||||
PartSize: partSize,
|
||||
Sign: &s3.AuthSignResult{
|
||||
Parts: []s3.SignPart{
|
||||
{
|
||||
PartNumber: 1,
|
||||
URL: rawURL,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
// Fragment upload
|
||||
upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if maxParts < 0 {
|
||||
maxParts = partNumber
|
||||
}
|
||||
var authSign *s3.AuthSignResult
|
||||
if maxParts > 0 {
|
||||
partNumbers := make([]int, maxParts)
|
||||
for i := 0; i < maxParts; i++ {
|
||||
partNumbers[i] = i + 1
|
||||
}
|
||||
authSign, err = c.impl.AuthSign(ctx, upload.UploadID, upload.Key, time.Hour*24, partNumbers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &InitiateUploadResult{
|
||||
UploadID: newMultipartUploadID(multipartUploadID{
|
||||
Type: UploadTypeMultipart,
|
||||
ID: upload.UploadID,
|
||||
Key: upload.Key,
|
||||
Size: size,
|
||||
Hash: hash,
|
||||
}),
|
||||
PartSize: partSize,
|
||||
Sign: authSign,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHashs []string) (*UploadResult, error) {
|
||||
defer log.ZDebug(ctx, "return")
|
||||
upload, err := parseMultipartUploadID(uploadID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if md5Sum := md5.Sum([]byte(strings.Join(partHashs, partSeparator))); hex.EncodeToString(md5Sum[:]) != upload.Hash {
|
||||
return nil, errors.New("md5 mismatching")
|
||||
}
|
||||
if info, err := c.StatObject(ctx, c.HashPath(upload.Hash)); err == nil {
|
||||
return &UploadResult{
|
||||
Key: info.Key,
|
||||
Size: info.Size,
|
||||
Hash: info.ETag,
|
||||
}, nil
|
||||
} else if !c.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
cleanObject := make(map[string]struct{})
|
||||
defer func() {
|
||||
for key := range cleanObject {
|
||||
_ = c.impl.DeleteObject(ctx, key)
|
||||
}
|
||||
}()
|
||||
var targetKey string
|
||||
switch upload.Type {
|
||||
case UploadTypeMultipart:
|
||||
parts := make([]s3.Part, len(partHashs))
|
||||
for i, part := range partHashs {
|
||||
parts[i] = s3.Part{
|
||||
PartNumber: i + 1,
|
||||
ETag: part,
|
||||
}
|
||||
}
|
||||
// todo: Validation size
|
||||
result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetKey = result.Key
|
||||
case UploadTypePresigned:
|
||||
uploadInfo, err := c.StatObject(ctx, upload.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cleanObject[uploadInfo.Key] = struct{}{}
|
||||
if uploadInfo.Size != upload.Size {
|
||||
return nil, errors.New("upload size mismatching")
|
||||
}
|
||||
md5Sum := md5.Sum([]byte(strings.Join([]string{uploadInfo.ETag}, partSeparator)))
|
||||
if md5val := hex.EncodeToString(md5Sum[:]); md5val != upload.Hash {
|
||||
return nil, errs.ErrArgs.Wrap(fmt.Sprintf("md5 mismatching %s != %s", md5val, upload.Hash))
|
||||
}
|
||||
// Prevents concurrent operations at this time that cause files to be overwritten
|
||||
copyInfo, err := c.impl.CopyObject(ctx, uploadInfo.Key, upload.Key+"."+c.UUID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cleanObject[copyInfo.Key] = struct{}{}
|
||||
if copyInfo.ETag != uploadInfo.ETag {
|
||||
return nil, errors.New("[concurrency]copy md5 mismatching")
|
||||
}
|
||||
hashCopyInfo, err := c.impl.CopyObject(ctx, copyInfo.Key, c.HashPath(upload.Hash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.ZInfo(ctx, "hashCopyInfo", "value", fmt.Sprintf("%+v", hashCopyInfo))
|
||||
targetKey = hashCopyInfo.Key
|
||||
default:
|
||||
return nil, errors.New("invalid upload id type")
|
||||
}
|
||||
if err := c.cache.DelS3Key(c.impl.Engine(), targetKey).ExecDel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UploadResult{
|
||||
Key: targetKey,
|
||||
Size: upload.Size,
|
||||
Hash: upload.Hash,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Controller) AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error) {
|
||||
upload, err := parseMultipartUploadID(uploadID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch upload.Type {
|
||||
case UploadTypeMultipart:
|
||||
return c.impl.AuthSign(ctx, upload.ID, upload.Key, time.Hour*24, partNumbers)
|
||||
case UploadTypePresigned:
|
||||
return nil, errors.New("presigned id not support auth sign")
|
||||
default:
|
||||
return nil, errors.New("invalid upload id type")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) IsNotFound(err error) bool {
|
||||
return c.impl.IsNotFound(err) || errs.ErrRecordNotFound.Is(err)
|
||||
}
|
||||
|
||||
func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||
if opt.Image != nil {
|
||||
opt.Filename = ""
|
||||
opt.ContentType = ""
|
||||
}
|
||||
return c.impl.AccessURL(ctx, name, expire, opt)
|
||||
}
|
||||
|
||||
func (c *Controller) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) {
|
||||
return c.impl.FormData(ctx, name, size, contentType, duration)
|
||||
}
|
||||
@@ -1,29 +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 cont
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
)
|
||||
|
||||
type HashAlreadyExistsError struct {
|
||||
Object *s3.ObjectInfo
|
||||
}
|
||||
|
||||
func (e *HashAlreadyExistsError) Error() string {
|
||||
return fmt.Sprintf("hash already exists: %s", e.Object.Key)
|
||||
}
|
||||
@@ -1,49 +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 cont
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type multipartUploadID struct {
|
||||
Type int `json:"a,omitempty"`
|
||||
ID string `json:"b,omitempty"`
|
||||
Key string `json:"c,omitempty"`
|
||||
Size int64 `json:"d,omitempty"`
|
||||
Hash string `json:"e,omitempty"`
|
||||
}
|
||||
|
||||
func newMultipartUploadID(id multipartUploadID) string {
|
||||
data, err := json.Marshal(id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
func parseMultipartUploadID(id string) (*multipartUploadID, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid multipart upload id: %w", err)
|
||||
}
|
||||
var upload multipartUploadID
|
||||
if err := json.Unmarshal(data, &upload); err != nil {
|
||||
return nil, fmt.Errorf("invalid multipart upload id: %w", err)
|
||||
}
|
||||
return &upload, nil
|
||||
}
|
||||
@@ -1,34 +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 cont
|
||||
|
||||
import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
|
||||
type InitiateUploadResult struct {
|
||||
// UploadID uniquely identifies the upload session for tracking and management purposes.
|
||||
UploadID string `json:"uploadID"`
|
||||
|
||||
// PartSize specifies the size of each part in a multipart upload. This is relevant for breaking down large uploads into manageable pieces.
|
||||
PartSize int64 `json:"partSize"`
|
||||
|
||||
// Sign contains the authentication and signature information necessary for securely uploading each part. This could include signed URLs or tokens.
|
||||
Sign *s3.AuthSignResult `json:"sign"`
|
||||
}
|
||||
|
||||
type UploadResult struct {
|
||||
Hash string `json:"hash"`
|
||||
Size int64 `json:"size"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
@@ -1,400 +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 cos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
)
|
||||
|
||||
const (
|
||||
minPartSize int64 = 1024 * 1024 * 1 // 1MB
|
||||
maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB
|
||||
maxNumSize int64 = 1000
|
||||
)
|
||||
|
||||
const (
|
||||
imagePng = "png"
|
||||
imageJpg = "jpg"
|
||||
imageJpeg = "jpeg"
|
||||
imageGif = "gif"
|
||||
imageWebp = "webp"
|
||||
)
|
||||
|
||||
const successCode = http.StatusOK
|
||||
|
||||
type Config struct {
|
||||
BucketURL string
|
||||
SecretID string
|
||||
SecretKey string
|
||||
SessionToken string
|
||||
PublicRead bool
|
||||
}
|
||||
|
||||
func NewCos(conf Config) (s3.Interface, error) {
|
||||
u, err := url.Parse(conf.BucketURL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
client := cos.NewClient(&cos.BaseURL{BucketURL: u}, &http.Client{
|
||||
Transport: &cos.AuthorizationTransport{
|
||||
SecretID: conf.SecretID,
|
||||
SecretKey: conf.SecretKey,
|
||||
SessionToken: conf.SessionToken,
|
||||
},
|
||||
})
|
||||
return &Cos{
|
||||
publicRead: conf.PublicRead,
|
||||
copyURL: u.Host + "/",
|
||||
client: client,
|
||||
credential: client.GetCredential(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Cos struct {
|
||||
publicRead bool
|
||||
copyURL string
|
||||
client *cos.Client
|
||||
credential *cos.Credential
|
||||
}
|
||||
|
||||
func (c *Cos) Engine() string {
|
||||
return "tencent-cos"
|
||||
}
|
||||
|
||||
func (c *Cos) PartLimit() *s3.PartLimit {
|
||||
return &s3.PartLimit{
|
||||
MinPartSize: minPartSize,
|
||||
MaxPartSize: maxPartSize,
|
||||
MaxNumSize: maxNumSize,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cos) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) {
|
||||
result, _, err := c.client.Object.InitiateMultipartUpload(ctx, name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.InitiateMultipartUploadResult{
|
||||
UploadID: result.UploadID,
|
||||
Bucket: result.Bucket,
|
||||
Key: result.Key,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Cos) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) {
|
||||
opts := &cos.CompleteMultipartUploadOptions{
|
||||
Parts: make([]cos.Object, len(parts)),
|
||||
}
|
||||
for i, part := range parts {
|
||||
opts.Parts[i] = cos.Object{
|
||||
PartNumber: part.PartNumber,
|
||||
ETag: strings.ReplaceAll(part.ETag, `"`, ``),
|
||||
}
|
||||
}
|
||||
result, _, err := c.client.Object.CompleteMultipartUpload(ctx, name, uploadID, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.CompleteMultipartUploadResult{
|
||||
Location: result.Location,
|
||||
Bucket: result.Bucket,
|
||||
Key: result.Key,
|
||||
ETag: result.ETag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Cos) 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("COS size must be less than the maximum allowed limit")
|
||||
}
|
||||
if size <= minPartSize*maxNumSize {
|
||||
return minPartSize, nil
|
||||
}
|
||||
partSize := size / maxNumSize
|
||||
if size%maxNumSize != 0 {
|
||||
partSize++
|
||||
}
|
||||
return partSize, nil
|
||||
}
|
||||
|
||||
func (c *Cos) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) {
|
||||
result := s3.AuthSignResult{
|
||||
URL: c.client.BaseURL.BucketURL.String() + "/" + cos.EncodeURIComponent(name),
|
||||
Query: url.Values{"uploadId": {uploadID}},
|
||||
Header: make(http.Header),
|
||||
Parts: make([]s3.SignPart, len(partNumbers)),
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, result.URL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cos.AddAuthorizationHeader(c.credential.SecretID, c.credential.SecretKey, c.credential.SessionToken, req, cos.NewAuthTime(expire))
|
||||
result.Header = req.Header
|
||||
for i, partNumber := range partNumbers {
|
||||
result.Parts[i] = s3.SignPart{
|
||||
PartNumber: partNumber,
|
||||
Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}},
|
||||
}
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *Cos) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) {
|
||||
rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodPut, name, c.credential.SecretID, c.credential.SecretKey, expire, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return rawURL.String(), nil
|
||||
}
|
||||
|
||||
func (c *Cos) DeleteObject(ctx context.Context, name string) error {
|
||||
_, err := c.client.Object.Delete(ctx, name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Cos) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) {
|
||||
if name != "" && name[0] == '/' {
|
||||
name = name[1:]
|
||||
}
|
||||
info, err := c.client.Object.Head(ctx, name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &s3.ObjectInfo{Key: name}
|
||||
if res.ETag = strings.ToLower(strings.ReplaceAll(info.Header.Get("ETag"), `"`, "")); res.ETag == "" {
|
||||
return nil, errors.New("StatObject etag not found")
|
||||
}
|
||||
if contentLengthStr := info.Header.Get("Content-Length"); contentLengthStr == "" {
|
||||
return nil, errors.New("StatObject content-length not found")
|
||||
} else {
|
||||
res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("StatObject content-length parse error: %w", err)
|
||||
}
|
||||
if res.Size < 0 {
|
||||
return nil, errors.New("StatObject content-length must be greater than 0")
|
||||
}
|
||||
}
|
||||
if lastModified := info.Header.Get("Last-Modified"); lastModified == "" {
|
||||
return nil, errors.New("StatObject last-modified not found")
|
||||
} else {
|
||||
res.LastModified, err = time.Parse(http.TimeFormat, lastModified)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("StatObject last-modified parse error: %w", err)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Cos) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) {
|
||||
sourceURL := c.copyURL + src
|
||||
result, _, err := c.client.Object.Copy(ctx, dst, sourceURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.CopyObjectInfo{
|
||||
Key: dst,
|
||||
ETag: strings.ReplaceAll(result.ETag, `"`, ``),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Cos) IsNotFound(err error) bool {
|
||||
switch e := errs.Unwrap(err).(type) {
|
||||
case *cos.ErrorResponse:
|
||||
return e.Response.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cos) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error {
|
||||
_, err := c.client.Object.AbortMultipartUpload(ctx, name, uploadID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Cos) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) {
|
||||
result, _, err := c.client.Object.ListParts(ctx, name, uploadID, &cos.ObjectListPartsOptions{
|
||||
MaxParts: strconv.Itoa(maxParts),
|
||||
PartNumberMarker: strconv.Itoa(partNumberMarker),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &s3.ListUploadedPartsResult{
|
||||
Key: result.Key,
|
||||
UploadID: result.UploadID,
|
||||
UploadedParts: make([]s3.UploadedPart, len(result.Parts)),
|
||||
}
|
||||
res.MaxParts, _ = strconv.Atoi(result.MaxParts)
|
||||
res.NextPartNumberMarker, _ = strconv.Atoi(result.NextPartNumberMarker)
|
||||
for i, part := range result.Parts {
|
||||
lastModified, _ := time.Parse(http.TimeFormat, part.LastModified)
|
||||
res.UploadedParts[i] = s3.UploadedPart{
|
||||
PartNumber: part.PartNumber,
|
||||
LastModified: lastModified,
|
||||
ETag: part.ETag,
|
||||
Size: part.Size,
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||
var imageMogr string
|
||||
var option cos.PresignedURLOptions
|
||||
if opt != nil {
|
||||
query := make(url.Values)
|
||||
if opt.Image != nil {
|
||||
// https://cloud.tencent.com/document/product/436/44880
|
||||
style := make([]string, 0, 2)
|
||||
wh := make([]string, 2)
|
||||
if opt.Image.Width > 0 {
|
||||
wh[0] = strconv.Itoa(opt.Image.Width)
|
||||
}
|
||||
if opt.Image.Height > 0 {
|
||||
wh[1] = strconv.Itoa(opt.Image.Height)
|
||||
}
|
||||
if opt.Image.Width > 0 || opt.Image.Height > 0 {
|
||||
style = append(style, strings.Join(wh, "x"))
|
||||
}
|
||||
switch opt.Image.Format {
|
||||
case
|
||||
imagePng,
|
||||
imageJpg,
|
||||
imageJpeg,
|
||||
imageGif,
|
||||
imageWebp:
|
||||
style = append(style, "format/"+opt.Image.Format)
|
||||
}
|
||||
if len(style) > 0 {
|
||||
imageMogr = "imageMogr2/thumbnail/" + strings.Join(style, "/") + "/ignore-error/1"
|
||||
}
|
||||
}
|
||||
if opt.ContentType != "" {
|
||||
query.Set("response-content-type", opt.ContentType)
|
||||
}
|
||||
if opt.Filename != "" {
|
||||
query.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
|
||||
}
|
||||
if len(query) > 0 {
|
||||
option.Query = &query
|
||||
}
|
||||
}
|
||||
if expire <= 0 {
|
||||
expire = time.Hour * 24 * 365 * 99 // 99 years
|
||||
} else if expire < time.Second {
|
||||
expire = time.Second
|
||||
}
|
||||
rawURL, err := c.getPresignedURL(ctx, name, expire, &option)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if imageMogr != "" {
|
||||
if rawURL.RawQuery == "" {
|
||||
rawURL.RawQuery = imageMogr
|
||||
} else {
|
||||
rawURL.RawQuery = rawURL.RawQuery + "&" + imageMogr
|
||||
}
|
||||
}
|
||||
return rawURL.String(), nil
|
||||
}
|
||||
|
||||
func (c *Cos) getPresignedURL(ctx context.Context, name string, expire time.Duration, opt *cos.PresignedURLOptions) (*url.URL, error) {
|
||||
if !c.publicRead {
|
||||
return c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, opt)
|
||||
}
|
||||
return c.client.Object.GetObjectURL(name), nil
|
||||
}
|
||||
|
||||
func (c *Cos) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) {
|
||||
// https://cloud.tencent.com/document/product/436/14690
|
||||
now := time.Now()
|
||||
expiration := now.Add(duration)
|
||||
keyTime := fmt.Sprintf("%d;%d", now.Unix(), expiration.Unix())
|
||||
conditions := []any{
|
||||
map[string]string{"q-sign-algorithm": "sha1"},
|
||||
map[string]string{"q-ak": c.credential.SecretID},
|
||||
map[string]string{"q-sign-time": keyTime},
|
||||
map[string]string{"key": name},
|
||||
}
|
||||
if contentType != "" {
|
||||
conditions = append(conditions, map[string]string{"Content-Type": contentType})
|
||||
}
|
||||
policy := map[string]any{
|
||||
"expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
|
||||
"conditions": conditions,
|
||||
}
|
||||
policyJson, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signKey := hmacSha1val(c.credential.SecretKey, keyTime)
|
||||
strToSign := sha1val(string(policyJson))
|
||||
signature := hmacSha1val(signKey, strToSign)
|
||||
|
||||
fd := &s3.FormData{
|
||||
URL: c.client.BaseURL.BucketURL.String(),
|
||||
File: "file",
|
||||
Expires: expiration,
|
||||
FormData: map[string]string{
|
||||
"policy": base64.StdEncoding.EncodeToString(policyJson),
|
||||
"q-sign-algorithm": "sha1",
|
||||
"q-ak": c.credential.SecretID,
|
||||
"q-key-time": keyTime,
|
||||
"q-signature": signature,
|
||||
"key": name,
|
||||
"success_action_status": strconv.Itoa(successCode),
|
||||
},
|
||||
SuccessCodes: []int{successCode},
|
||||
}
|
||||
if contentType != "" {
|
||||
fd.FormData["Content-Type"] = contentType
|
||||
}
|
||||
if c.credential.SessionToken != "" {
|
||||
fd.FormData["x-cos-security-token"] = c.credential.SessionToken
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
func hmacSha1val(key, msg string) string {
|
||||
v := hmac.New(sha1.New, []byte(key))
|
||||
v.Write([]byte(msg))
|
||||
return hex.EncodeToString(v.Sum(nil))
|
||||
}
|
||||
|
||||
func sha1val(msg string) string {
|
||||
sha1Hash := sha1.New()
|
||||
sha1Hash.Write([]byte(msg))
|
||||
return hex.EncodeToString(sha1Hash.Sum(nil))
|
||||
}
|
||||
@@ -1,27 +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 cos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
)
|
||||
|
||||
//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 any, optQuery any, optHeader any) (req *http.Request, err error)
|
||||
@@ -1,120 +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 minio
|
||||
|
||||
import (
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
|
||||
_ "golang.org/x/image/bmp"
|
||||
_ "golang.org/x/image/tiff"
|
||||
_ "golang.org/x/image/webp"
|
||||
)
|
||||
|
||||
const (
|
||||
formatPng = "png"
|
||||
formatJpeg = "jpeg"
|
||||
formatJpg = "jpg"
|
||||
formatGif = "gif"
|
||||
)
|
||||
|
||||
func ImageStat(reader io.Reader) (image.Image, string, error) {
|
||||
return image.Decode(reader)
|
||||
}
|
||||
|
||||
func ImageWidthHeight(img image.Image) (int, int) {
|
||||
bounds := img.Bounds().Max
|
||||
return bounds.X, bounds.Y
|
||||
}
|
||||
|
||||
func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
|
||||
bounds := img.Bounds()
|
||||
imgWidth := bounds.Max.X
|
||||
imgHeight := bounds.Max.Y
|
||||
|
||||
// Calculating scaling
|
||||
scaleWidth := float64(maxWidth) / float64(imgWidth)
|
||||
scaleHeight := float64(maxHeight) / float64(imgHeight)
|
||||
|
||||
// If both are 0, then no scaling is done and the original image is returned
|
||||
if maxWidth == 0 && maxHeight == 0 {
|
||||
return img
|
||||
}
|
||||
|
||||
// If both width and height are greater than 0, select a smaller zoom ratio to maintain the aspect ratio
|
||||
if maxWidth > 0 && maxHeight > 0 {
|
||||
scale := scaleWidth
|
||||
if scaleHeight < scaleWidth {
|
||||
scale = scaleHeight
|
||||
}
|
||||
|
||||
// Calculate Thumbnail Size
|
||||
thumbnailWidth := int(float64(imgWidth) * scale)
|
||||
thumbnailHeight := int(float64(imgHeight) * scale)
|
||||
|
||||
// Thumbnails are generated using the Resample method of the "image" library.
|
||||
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||
for y := 0; y < thumbnailHeight; y++ {
|
||||
for x := 0; x < thumbnailWidth; x++ {
|
||||
srcX := int(float64(x) / scale)
|
||||
srcY := int(float64(y) / scale)
|
||||
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
}
|
||||
|
||||
// If only width or height is specified, thumbnails are generated based on the maximum not to exceed rule
|
||||
if maxWidth > 0 {
|
||||
thumbnailWidth := maxWidth
|
||||
thumbnailHeight := int(float64(imgHeight) * scaleWidth)
|
||||
|
||||
// Thumbnails are generated using the Resample method of the "image" library.
|
||||
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||
for y := 0; y < thumbnailHeight; y++ {
|
||||
for x := 0; x < thumbnailWidth; x++ {
|
||||
srcX := int(float64(x) / scaleWidth)
|
||||
srcY := int(float64(y) / scaleWidth)
|
||||
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
}
|
||||
|
||||
if maxHeight > 0 {
|
||||
thumbnailWidth := int(float64(imgWidth) * scaleHeight)
|
||||
thumbnailHeight := maxHeight
|
||||
|
||||
// Thumbnails are generated using the Resample method of the "image" library.
|
||||
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
|
||||
for y := 0; y < thumbnailHeight; y++ {
|
||||
for x := 0; x < thumbnailWidth; x++ {
|
||||
srcX := int(float64(x) / scaleHeight)
|
||||
srcY := int(float64(y) / scaleHeight)
|
||||
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
}
|
||||
|
||||
// By default, the original image is returned
|
||||
return img
|
||||
}
|
||||
@@ -1,25 +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 minio
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/minio/minio-go/v7"
|
||||
)
|
||||
|
||||
//go:linkname makeTargetURL github.com/minio/minio-go/v7.(*Client).makeTargetURL
|
||||
func makeTargetURL(client *minio.Client, bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error)
|
||||
@@ -1,499 +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 minio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
"github.com/minio/minio-go/v7/pkg/signer"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
)
|
||||
|
||||
const (
|
||||
unsignedPayload = "UNSIGNED-PAYLOAD"
|
||||
)
|
||||
|
||||
const (
|
||||
minPartSize int64 = 1024 * 1024 * 5 // 5MB
|
||||
maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB
|
||||
maxNumSize int64 = 10000
|
||||
)
|
||||
|
||||
const (
|
||||
maxImageWidth = 1024
|
||||
maxImageHeight = 1024
|
||||
maxImageSize = 1024 * 1024 * 50
|
||||
imageThumbnailPath = "openim/thumbnail"
|
||||
)
|
||||
|
||||
const successCode = http.StatusOK
|
||||
|
||||
type Config struct {
|
||||
Bucket string
|
||||
Endpoint string
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
SessionToken string
|
||||
SignEndpoint string
|
||||
PublicRead bool
|
||||
}
|
||||
|
||||
func NewMinio(cache cache.MinioCache, conf Config) (s3.Interface, error) {
|
||||
u, err := url.Parse(conf.Endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := &minio.Options{
|
||||
Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
|
||||
Secure: u.Scheme == "https",
|
||||
}
|
||||
client, err := minio.New(u.Host, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := &Minio{
|
||||
conf: conf,
|
||||
bucket: conf.Bucket,
|
||||
core: &minio.Core{Client: client},
|
||||
lock: &sync.Mutex{},
|
||||
init: false,
|
||||
cache: cache,
|
||||
}
|
||||
if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
|
||||
m.opts = opts
|
||||
m.sign = m.core.Client
|
||||
m.prefix = u.Path
|
||||
u.Path = ""
|
||||
conf.Endpoint = u.String()
|
||||
m.signEndpoint = conf.Endpoint
|
||||
} else {
|
||||
su, err := url.Parse(conf.SignEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.opts = &minio.Options{
|
||||
Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
|
||||
Secure: su.Scheme == "https",
|
||||
}
|
||||
m.sign, err = minio.New(su.Host, m.opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.prefix = su.Path
|
||||
su.Path = ""
|
||||
conf.SignEndpoint = su.String()
|
||||
m.signEndpoint = conf.SignEndpoint
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
fmt.Println("init minio error:", err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
type Minio struct {
|
||||
conf Config
|
||||
bucket string
|
||||
signEndpoint string
|
||||
location string
|
||||
opts *minio.Options
|
||||
core *minio.Core
|
||||
sign *minio.Client
|
||||
lock sync.Locker
|
||||
init bool
|
||||
prefix string
|
||||
cache cache.MinioCache
|
||||
}
|
||||
|
||||
func (m *Minio) initMinio(ctx context.Context) error {
|
||||
if m.init {
|
||||
return nil
|
||||
}
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
if m.init {
|
||||
return nil
|
||||
}
|
||||
exists, err := m.core.Client.BucketExists(ctx, m.conf.Bucket)
|
||||
if err != nil {
|
||||
return fmt.Errorf("check bucket exists error: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
if err = m.core.Client.MakeBucket(ctx, m.conf.Bucket, minio.MakeBucketOptions{}); err != nil {
|
||||
return fmt.Errorf("make bucket error: %w", err)
|
||||
}
|
||||
}
|
||||
if m.conf.PublicRead {
|
||||
policy := fmt.Sprintf(
|
||||
`{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`,
|
||||
m.conf.Bucket,
|
||||
)
|
||||
if err = m.core.Client.SetBucketPolicy(ctx, m.conf.Bucket, policy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
m.location, err = m.core.Client.GetBucketLocation(ctx, m.conf.Bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func() {
|
||||
if m.conf.SignEndpoint == "" || m.conf.SignEndpoint == m.conf.Endpoint {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
m.sign = m.core.Client
|
||||
log.ZWarn(
|
||||
context.Background(),
|
||||
"set sign bucket location cache panic",
|
||||
errors.New("failed to get private field value"),
|
||||
"recover",
|
||||
fmt.Sprintf("%+v", r),
|
||||
"development version",
|
||||
"github.com/minio/minio-go/v7 v7.0.61",
|
||||
)
|
||||
}
|
||||
}()
|
||||
blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache")
|
||||
vblc := reflect.New(reflect.PtrTo(blc.Type()))
|
||||
*(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr())
|
||||
vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(m.conf.Bucket, m.location)
|
||||
}()
|
||||
m.init = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Minio) Engine() string {
|
||||
return "minio"
|
||||
}
|
||||
|
||||
func (m *Minio) PartLimit() *s3.PartLimit {
|
||||
return &s3.PartLimit{
|
||||
MinPartSize: minPartSize,
|
||||
MaxPartSize: maxPartSize,
|
||||
MaxNumSize: maxNumSize,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Minio) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uploadID, err := m.core.NewMultipartUpload(ctx, m.bucket, name, minio.PutObjectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.InitiateMultipartUploadResult{
|
||||
Bucket: m.bucket,
|
||||
Key: name,
|
||||
UploadID: uploadID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Minio) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
minioParts := make([]minio.CompletePart, len(parts))
|
||||
for i, part := range parts {
|
||||
minioParts[i] = minio.CompletePart{
|
||||
PartNumber: part.PartNumber,
|
||||
ETag: strings.ToLower(part.ETag),
|
||||
}
|
||||
}
|
||||
upload, err := m.core.CompleteMultipartUpload(ctx, m.bucket, name, uploadID, minioParts, minio.PutObjectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.delObjectImageInfoKey(ctx, name, upload.Size)
|
||||
return &s3.CompleteMultipartUploadResult{
|
||||
Location: upload.Location,
|
||||
Bucket: upload.Bucket,
|
||||
Key: upload.Key,
|
||||
ETag: strings.ToLower(upload.ETag),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Minio) 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("MINIO size must be less than the maximum allowed limit")
|
||||
}
|
||||
if size <= minPartSize*maxNumSize {
|
||||
return minPartSize, nil
|
||||
}
|
||||
partSize := size / maxNumSize
|
||||
if size%maxNumSize != 0 {
|
||||
partSize++
|
||||
}
|
||||
return partSize, nil
|
||||
}
|
||||
|
||||
func (m *Minio) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
creds, err := m.opts.Creds.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := s3.AuthSignResult{
|
||||
URL: m.signEndpoint + "/" + m.bucket + "/" + name,
|
||||
Query: url.Values{"uploadId": {uploadID}},
|
||||
Parts: make([]s3.SignPart, len(partNumbers)),
|
||||
}
|
||||
for i, partNumber := range partNumbers {
|
||||
rawURL := result.URL + "?partNumber=" + strconv.Itoa(partNumber) + "&uploadId=" + uploadID
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Set("X-Amz-Content-Sha256", unsignedPayload)
|
||||
request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, m.location, nil)
|
||||
result.Parts[i] = s3.SignPart{
|
||||
PartNumber: partNumber,
|
||||
Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}},
|
||||
Header: request.Header,
|
||||
}
|
||||
}
|
||||
if m.prefix != "" {
|
||||
result.URL = m.signEndpoint + m.prefix + "/" + m.bucket + "/" + name
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (m *Minio) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
rawURL, err := m.sign.PresignedPutObject(ctx, m.bucket, name, expire)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if m.prefix != "" {
|
||||
rawURL.Path = path.Join(m.prefix, rawURL.Path)
|
||||
}
|
||||
return rawURL.String(), nil
|
||||
}
|
||||
|
||||
func (m *Minio) DeleteObject(ctx context.Context, name string) error {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return m.core.Client.RemoveObject(ctx, m.bucket, name, minio.RemoveObjectOptions{})
|
||||
}
|
||||
|
||||
func (m *Minio) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := m.core.Client.StatObject(ctx, m.bucket, name, minio.StatObjectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.ObjectInfo{
|
||||
ETag: strings.ToLower(info.ETag),
|
||||
Key: info.Key,
|
||||
Size: info.Size,
|
||||
LastModified: info.LastModified,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Minio) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := m.core.Client.CopyObject(ctx, minio.CopyDestOptions{
|
||||
Bucket: m.bucket,
|
||||
Object: dst,
|
||||
}, minio.CopySrcOptions{
|
||||
Bucket: m.bucket,
|
||||
Object: src,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s3.CopyObjectInfo{
|
||||
Key: dst,
|
||||
ETag: strings.ToLower(result.ETag),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Minio) IsNotFound(err error) bool {
|
||||
switch e := errs.Unwrap(err).(type) {
|
||||
case minio.ErrorResponse:
|
||||
return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
|
||||
case *minio.ErrorResponse:
|
||||
return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Minio) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return m.core.AbortMultipartUpload(ctx, m.bucket, name, uploadID)
|
||||
}
|
||||
|
||||
func (m *Minio) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := m.core.ListObjectParts(ctx, m.bucket, name, uploadID, partNumberMarker, maxParts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &s3.ListUploadedPartsResult{
|
||||
Key: result.Key,
|
||||
UploadID: result.UploadID,
|
||||
MaxParts: result.MaxParts,
|
||||
NextPartNumberMarker: result.NextPartNumberMarker,
|
||||
UploadedParts: make([]s3.UploadedPart, len(result.ObjectParts)),
|
||||
}
|
||||
for i, part := range result.ObjectParts {
|
||||
res.UploadedParts[i] = s3.UploadedPart{
|
||||
PartNumber: part.PartNumber,
|
||||
LastModified: part.LastModified,
|
||||
ETag: part.ETag,
|
||||
Size: part.Size,
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (m *Minio) PresignedGetObject(ctx context.Context, name string, expire time.Duration, query url.Values) (string, error) {
|
||||
if expire <= 0 {
|
||||
expire = time.Hour * 24 * 365 * 99 // 99 years
|
||||
} else if expire < time.Second {
|
||||
expire = time.Second
|
||||
}
|
||||
var (
|
||||
rawURL *url.URL
|
||||
err error
|
||||
)
|
||||
if m.conf.PublicRead {
|
||||
rawURL, err = makeTargetURL(m.sign, m.bucket, name, m.location, false, query)
|
||||
} else {
|
||||
rawURL, err = m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if m.prefix != "" {
|
||||
rawURL.Path = path.Join(m.prefix, rawURL.Path)
|
||||
}
|
||||
return rawURL.String(), nil
|
||||
}
|
||||
|
||||
func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqParams := make(url.Values)
|
||||
if opt != nil {
|
||||
if opt.ContentType != "" {
|
||||
reqParams.Set("response-content-type", opt.ContentType)
|
||||
}
|
||||
if opt.Filename != "" {
|
||||
reqParams.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
|
||||
}
|
||||
}
|
||||
if opt.Image == nil || (opt.Image.Width < 0 && opt.Image.Height < 0 && opt.Image.Format == "") || (opt.Image.Width > maxImageWidth || opt.Image.Height > maxImageHeight) {
|
||||
return m.PresignedGetObject(ctx, name, expire, reqParams)
|
||||
}
|
||||
return m.getImageThumbnailURL(ctx, name, expire, opt.Image)
|
||||
}
|
||||
|
||||
func (m *Minio) getObjectData(ctx context.Context, name string, limit int64) ([]byte, error) {
|
||||
object, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer object.Close()
|
||||
if limit < 0 {
|
||||
return io.ReadAll(object)
|
||||
}
|
||||
return io.ReadAll(io.LimitReader(object, limit))
|
||||
}
|
||||
|
||||
func (m *Minio) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) {
|
||||
if err := m.initMinio(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy := minio.NewPostPolicy()
|
||||
if err := policy.SetKey(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expires := time.Now().Add(duration)
|
||||
if err := policy.SetExpires(expires); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size > 0 {
|
||||
if err := policy.SetContentLengthRange(0, size); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := policy.SetSuccessStatusAction(strconv.Itoa(successCode)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if contentType != "" {
|
||||
if err := policy.SetContentType(contentType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := policy.SetBucket(m.bucket); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, fd, err := m.core.PresignedPostPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sign, err := url.Parse(m.signEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.Scheme = sign.Scheme
|
||||
u.Host = sign.Host
|
||||
return &s3.FormData{
|
||||
URL: u.String(),
|
||||
File: "file",
|
||||
Header: nil,
|
||||
FormData: fd,
|
||||
Expires: expires,
|
||||
SuccessCodes: []int{successCode},
|
||||
}, nil
|
||||
}
|
||||
@@ -1,150 +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 minio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
)
|
||||
|
||||
func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire time.Duration, opt *s3.Image) (string, error) {
|
||||
var img image.Image
|
||||
info, err := m.cache.GetImageObjectKeyInfo(ctx, name, func(ctx context.Context) (info *cache.MinioImageInfo, err error) {
|
||||
info, img, err = m.getObjectImageInfo(ctx, name)
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !info.IsImg {
|
||||
return "", errs.ErrData.Wrap("object not image")
|
||||
}
|
||||
if opt.Width > info.Width || opt.Width <= 0 {
|
||||
opt.Width = info.Width
|
||||
}
|
||||
if opt.Height > info.Height || opt.Height <= 0 {
|
||||
opt.Height = info.Height
|
||||
}
|
||||
opt.Format = strings.ToLower(opt.Format)
|
||||
if opt.Format == formatJpg {
|
||||
opt.Format = formatJpeg
|
||||
}
|
||||
switch opt.Format {
|
||||
case formatPng, formatJpeg, formatGif:
|
||||
default:
|
||||
opt.Format = ""
|
||||
}
|
||||
reqParams := make(url.Values)
|
||||
if opt.Width == info.Width && opt.Height == info.Height && (opt.Format == info.Format || opt.Format == "") {
|
||||
reqParams.Set("response-content-type", "image/"+info.Format)
|
||||
return m.PresignedGetObject(ctx, name, expire, reqParams)
|
||||
}
|
||||
if opt.Format == "" {
|
||||
switch opt.Format {
|
||||
case formatGif:
|
||||
opt.Format = formatGif
|
||||
case formatJpeg:
|
||||
opt.Format = formatJpeg
|
||||
case formatPng:
|
||||
opt.Format = formatPng
|
||||
default:
|
||||
opt.Format = formatPng
|
||||
}
|
||||
}
|
||||
key, err := m.cache.GetThumbnailKey(ctx, name, opt.Format, opt.Width, opt.Height, func(ctx context.Context) (string, error) {
|
||||
if img == nil {
|
||||
var reader *minio.Object
|
||||
reader, err = m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer reader.Close()
|
||||
img, _, err = ImageStat(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
thumbnail := resizeImage(img, opt.Width, opt.Height)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
switch opt.Format {
|
||||
case formatPng:
|
||||
err = png.Encode(buf, thumbnail)
|
||||
case formatJpeg:
|
||||
err = jpeg.Encode(buf, thumbnail, nil)
|
||||
case formatGif:
|
||||
err = gif.Encode(buf, thumbnail, nil)
|
||||
}
|
||||
cacheKey := filepath.Join(imageThumbnailPath, info.Etag, fmt.Sprintf("image_w%d_h%d.%s", opt.Width, opt.Height, opt.Format))
|
||||
if _, err = m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cacheKey, nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqParams.Set("response-content-type", "image/"+opt.Format)
|
||||
return m.PresignedGetObject(ctx, key, expire, reqParams)
|
||||
}
|
||||
|
||||
func (m *Minio) getObjectImageInfo(ctx context.Context, name string) (*cache.MinioImageInfo, image.Image, error) {
|
||||
fileInfo, err := m.StatObject(ctx, name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if fileInfo.Size > maxImageSize {
|
||||
return nil, nil, errors.New("file size too large")
|
||||
}
|
||||
imageData, err := m.getObjectData(ctx, name, fileInfo.Size)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var info cache.MinioImageInfo
|
||||
imageInfo, format, err := ImageStat(bytes.NewReader(imageData))
|
||||
if err == nil {
|
||||
info.IsImg = true
|
||||
info.Format = format
|
||||
info.Width, info.Height = ImageWidthHeight(imageInfo)
|
||||
} else {
|
||||
info.IsImg = false
|
||||
}
|
||||
info.Etag = fileInfo.ETag
|
||||
return &info, imageInfo, nil
|
||||
}
|
||||
|
||||
func (m *Minio) delObjectImageInfoKey(ctx context.Context, key string, size int64) {
|
||||
if size > 0 && size > maxImageSize {
|
||||
return
|
||||
}
|
||||
if err := m.cache.DelObjectImageInfoKey(key).ExecDel(ctx); err != nil {
|
||||
log.ZError(ctx, "DelObjectImageInfoKey failed", err, "key", key)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user