mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-12-02 10:18:45 +08:00
feat: Some of the notes were translated
This commit is contained in:
parent
20b8a7cc10
commit
7b0cc91dd9
@ -44,7 +44,7 @@ import (
|
||||
)
|
||||
|
||||
func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine {
|
||||
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // 默认RPC中间件
|
||||
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // Default RPC middleware
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.New()
|
||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||
|
||||
@ -279,7 +279,7 @@ func (ws *WsServer) registerClient(client *Client) {
|
||||
log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID)
|
||||
if clientOK {
|
||||
ws.clients.Set(client.UserID, client)
|
||||
// 已经有同平台的连接存在
|
||||
// There is already a connection to the platform
|
||||
log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients))
|
||||
ws.onlineUserConnNum.Add(1)
|
||||
} else {
|
||||
|
||||
@ -19,15 +19,15 @@ import "time"
|
||||
type (
|
||||
Option func(opt *configs)
|
||||
configs struct {
|
||||
// 长连接监听端口
|
||||
// Long connection listening port
|
||||
port int
|
||||
// 长连接允许最大链接数
|
||||
// Maximum number of connections allowed for long connection
|
||||
maxConnNum int64
|
||||
// 连接握手超时时间
|
||||
// Connection handshake timeout
|
||||
handshakeTimeout time.Duration
|
||||
// 允许消息最大长度
|
||||
// Maximum length allowed for messages
|
||||
messageMaxMsgLength int
|
||||
// websocket write buffer, default: 4096, 4kb.
|
||||
// Websocket write buffer, default: 4096, 4kb.
|
||||
writeBufferSize int
|
||||
}
|
||||
)
|
||||
|
||||
@ -229,7 +229,8 @@ func (p *Pusher) Push2SuperGroup(ctx context.Context, groupID string, msg *sdkws
|
||||
}(groupID, kickedUsers)
|
||||
pushToUserIDs = append(pushToUserIDs, kickedUsers...)
|
||||
case constant.GroupDismissedNotification:
|
||||
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) { // 消息先到,通知后到
|
||||
// Messages arrive first, notifications arrive later
|
||||
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) {
|
||||
var tips sdkws.GroupDismissedTips
|
||||
if p.UnmarshalNotificationElem(msg.Content, &tips) != nil {
|
||||
return err
|
||||
|
||||
@ -310,7 +310,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
|
||||
unequal++
|
||||
}
|
||||
}
|
||||
if err := c.conversationDatabase.SetUsersConversationFiledTx(ctx, req.UserIDs, &conversation, m); err != nil {
|
||||
if err := c.conversationDatabase.SetUsersConversationFieldTx(ctx, req.UserIDs, &conversation, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unequal > 0 {
|
||||
@ -321,7 +321,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
|
||||
return &pbconversation.SetConversationsResp{}, nil
|
||||
}
|
||||
|
||||
// 获取超级大群开启免打扰的用户ID.
|
||||
// Get user IDs with "Do Not Disturb" enabled in super large groups.
|
||||
func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) {
|
||||
//userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID)
|
||||
//if err != nil {
|
||||
@ -378,7 +378,7 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
|
||||
}
|
||||
|
||||
func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
|
||||
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, req.OwnerUserID, req.ConversationID,
|
||||
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
|
||||
map[string]any{"max_seq": req.MaxSeq}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -278,6 +278,7 @@ func (s *friendServer) GetDesignatedFriends(ctx context.Context, req *pbfriend.G
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Get the list of friend requests sent out proactively.
|
||||
func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
|
||||
req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) {
|
||||
friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID)
|
||||
@ -292,7 +293,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ok 获取接收到的好友申请(即别人主动申请的).
|
||||
// Get received friend requests (i.e., those initiated by others).
|
||||
func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
|
||||
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
|
||||
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
|
||||
@ -311,7 +312,6 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ok 获取主动发出去的好友申请列表.
|
||||
func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
|
||||
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
|
||||
resp = &pbfriend.GetPaginationFriendsApplyFromResp{}
|
||||
|
||||
@ -765,8 +765,8 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
|
||||
return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
|
||||
}
|
||||
var inGroup bool
|
||||
if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil {
|
||||
inGroup = true // 已经在群里了
|
||||
if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil {
|
||||
inGroup = true // Already in group
|
||||
} else if !s.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 根据配置文件策略选择 oss 方式
|
||||
// Select based on the configuration file strategy
|
||||
enable := config.Config.Object.Enable
|
||||
var o s3.Interface
|
||||
switch config.Config.Object.Enable {
|
||||
|
||||
@ -58,9 +58,9 @@ import (
|
||||
// continue
|
||||
// }
|
||||
// if len(seqs) > 0 {
|
||||
// if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err
|
||||
// if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]interface{}{"latest_msg_destruct_time": now}); err
|
||||
// != nil {
|
||||
// log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
|
||||
// log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
|
||||
// continue
|
||||
// }
|
||||
// if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {
|
||||
@ -139,8 +139,8 @@ func (c *MsgTool) ConversationsDestructMsgs() {
|
||||
continue
|
||||
}
|
||||
if len(seqs) > 0 {
|
||||
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil {
|
||||
log.ZError(ctx, "updateUsersConversationFiled failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
|
||||
if err := c.conversationDatabase.UpdateUsersConversationField(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil {
|
||||
log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
|
||||
continue
|
||||
}
|
||||
if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {
|
||||
|
||||
@ -30,9 +30,9 @@ import (
|
||||
)
|
||||
|
||||
type AuthDatabase interface {
|
||||
// 结果为空 不返回错误
|
||||
// If the result is empty, no error is returned.
|
||||
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
|
||||
// 创建token
|
||||
// Create token
|
||||
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
|
||||
}
|
||||
|
||||
@ -47,16 +47,12 @@ func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int
|
||||
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire}
|
||||
}
|
||||
|
||||
// 结果为空 不返回错误.
|
||||
func (a *authDatabase) GetTokensWithoutError(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
platformID int,
|
||||
) (map[string]int, error) {
|
||||
// If the result is empty
|
||||
func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
|
||||
return a.cache.GetTokensWithoutError(ctx, userID, platformID)
|
||||
}
|
||||
|
||||
// 创建token.
|
||||
// Create Token
|
||||
func (a *authDatabase) CreateToken(ctx context.Context, userID string, platformID int) (string, error) {
|
||||
tokens, err := a.cache.GetTokensWithoutError(ctx, userID, platformID)
|
||||
if err != nil {
|
||||
@ -80,7 +76,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)
|
||||
return "", errs.Wrap(err, "token.SignedString")
|
||||
}
|
||||
return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken)
|
||||
}
|
||||
|
||||
@ -32,32 +32,40 @@ import (
|
||||
)
|
||||
|
||||
type ConversationDatabase interface {
|
||||
// UpdateUserConversationFiled 更新用户该会话的属性信息
|
||||
UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error
|
||||
// CreateConversation 创建一批新的会话
|
||||
// UpdateUsersConversationField updates the properties of a conversation for specified users.
|
||||
UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error
|
||||
// CreateConversation creates a batch of new conversations.
|
||||
CreateConversation(ctx context.Context, conversations []*relationtb.ConversationModel) error
|
||||
// SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作
|
||||
// SyncPeerUserPrivateConversationTx ensures transactional operation while syncing private conversations between peers.
|
||||
SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationtb.ConversationModel) error
|
||||
// FindConversations 根据会话ID获取某个用户的多个会话
|
||||
// FindConversations retrieves multiple conversations of a user by conversation IDs.
|
||||
FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationtb.ConversationModel, error)
|
||||
// FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID
|
||||
//FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
|
||||
// GetUserAllConversation 获取一个用户在服务器上所有的会话
|
||||
// GetUserAllConversation fetches all conversations of a user on the server.
|
||||
GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationtb.ConversationModel, error)
|
||||
// SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性
|
||||
// SetUserConversations sets multiple conversation properties for a user, creates new conversations if they do not exist, or updates them otherwise. This operation is atomic.
|
||||
SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationtb.ConversationModel) error
|
||||
// SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作
|
||||
SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) error
|
||||
// SetUsersConversationFieldTx updates a specific field for multiple users' conversations, creating new conversations if they do not exist, or updates them otherwise. This operation is transactional.
|
||||
SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) error
|
||||
// CreateGroupChatConversation creates a group chat conversation for the specified group ID and user IDs.
|
||||
CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error
|
||||
// GetConversationIDs retrieves conversation IDs for a given user.
|
||||
GetConversationIDs(ctx context.Context, userID string) ([]string, error)
|
||||
// GetUserConversationIDsHash gets the hash of conversation IDs for a given user.
|
||||
GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error)
|
||||
// GetAllConversationIDs fetches all conversation IDs.
|
||||
GetAllConversationIDs(ctx context.Context) ([]string, error)
|
||||
// GetAllConversationIDsNumber returns the number of all conversation IDs.
|
||||
GetAllConversationIDsNumber(ctx context.Context) (int64, error)
|
||||
// PageConversationIDs paginates through conversation IDs based on the specified pagination settings.
|
||||
PageConversationIDs(ctx context.Context, pagination pagination.Pagination) (conversationIDs []string, err error)
|
||||
//GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
|
||||
// GetConversationsByConversationID retrieves conversations by their IDs.
|
||||
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationtb.ConversationModel, error)
|
||||
// GetConversationIDsNeedDestruct fetches conversations that need to be destructed based on specific criteria.
|
||||
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)
|
||||
}
|
||||
|
||||
func NewConversationDatabase(conversation relationtb.ConversationModelInterface, cache cache.ConversationCache, tx tx.CtxTx) ConversationDatabase {
|
||||
@ -74,7 +82,7 @@ type conversationDatabase struct {
|
||||
tx tx.CtxTx
|
||||
}
|
||||
|
||||
func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, filedMap map[string]any) (err error) {
|
||||
func (c *conversationDatabase) SetUsersConversationFieldTx(ctx context.Context, userIDs []string, conversation *relationtb.ConversationModel, fieldMap map[string]any) (err error) {
|
||||
return c.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
cache := c.cache.NewCache()
|
||||
if conversation.GroupID != "" {
|
||||
@ -85,22 +93,22 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
if len(haveUserIDs) > 0 {
|
||||
_, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap)
|
||||
_, err = c.conversationDB.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, fieldMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cache = cache.DelUsersConversation(conversation.ConversationID, haveUserIDs...)
|
||||
if _, ok := filedMap["has_read_seq"]; ok {
|
||||
if _, ok := fieldMap["has_read_seq"]; ok {
|
||||
for _, userID := range haveUserIDs {
|
||||
cache = cache.DelUserAllHasReadSeqs(userID, conversation.ConversationID)
|
||||
}
|
||||
}
|
||||
if _, ok := filedMap["recv_msg_opt"]; ok {
|
||||
if _, ok := fieldMap["recv_msg_opt"]; ok {
|
||||
cache = cache.DelConversationNotReceiveMessageUserIDs(conversation.ConversationID)
|
||||
}
|
||||
}
|
||||
NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs)
|
||||
log.ZDebug(ctx, "SetUsersConversationFiledTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
|
||||
log.ZDebug(ctx, "SetUsersConversationFieldTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
|
||||
var conversations []*relationtb.ConversationModel
|
||||
now := time.Now()
|
||||
for _, v := range NotUserIDs {
|
||||
@ -123,7 +131,7 @@ func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error {
|
||||
func (c *conversationDatabase) UpdateUsersConversationField(ctx context.Context, userIDs []string, conversationID string, args map[string]any) error {
|
||||
_, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -16,6 +16,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
@ -89,20 +90,30 @@ func NewFriendDatabase(friend relation.FriendModelInterface, friendRequest relat
|
||||
return &friendDatabase{friend: friend, friendRequest: friendRequest, cache: cache, tx: tx}
|
||||
}
|
||||
|
||||
// ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true).
|
||||
// CheckIn verifies if user2 is in user1's friend list (inUser1Friends returns true) and
|
||||
// if user1 is in user2's friend list (inUser2Friends returns true).
|
||||
func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) {
|
||||
// Retrieve friend IDs of userID1 from the cache
|
||||
userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID1, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve friend IDs of userID2 from the cache
|
||||
userID2FriendIDs, err := f.cache.GetFriendIDs(ctx, userID2)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error retrieving friend IDs for user %s: %w", userID2, err)
|
||||
return
|
||||
}
|
||||
return utils.IsContain(userID2, userID1FriendIDs), utils.IsContain(userID1, userID2FriendIDs), nil
|
||||
|
||||
// Check if userID2 is in userID1's friend list and vice versa
|
||||
inUser1Friends = utils.IsContain(userID2, userID1FriendIDs)
|
||||
inUser2Friends = utils.IsContain(userID1, userID2FriendIDs)
|
||||
return inUser1Friends, inUser2Friends, nil
|
||||
}
|
||||
|
||||
// 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增.
|
||||
// AddFriendRequest adds or updates a friend request
|
||||
func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) {
|
||||
return f.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
_, err := f.friendRequest.Take(ctx, fromUserID, toUserID)
|
||||
@ -170,26 +181,37 @@ func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string,
|
||||
})
|
||||
}
|
||||
|
||||
// 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝.
|
||||
func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
|
||||
// RefuseFriendRequest rejects a friend request. It first checks for an existing, unprocessed request.
|
||||
// If no such request exists, it returns an error. Otherwise, it marks the request as refused.
|
||||
func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) error {
|
||||
// Attempt to retrieve the friend request from the database.
|
||||
fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to retrieve friend request from %s to %s: %w", friendRequest.FromUserID, friendRequest.ToUserID, err)
|
||||
}
|
||||
|
||||
// Check if the friend request has already been handled.
|
||||
if fr.HandleResult != 0 {
|
||||
return errs.ErrArgs.Wrap("the friend request has been processed")
|
||||
return fmt.Errorf("friend request from %s to %s has already been processed", friendRequest.FromUserID, friendRequest.ToUserID)
|
||||
}
|
||||
log.ZDebug(ctx, "refuse friend request", "friendRequest db", fr, "friendRequest arg", friendRequest)
|
||||
|
||||
// Log the action of refusing the friend request for debugging and auditing purposes.
|
||||
log.ZDebug(ctx, "Refusing friend request", map[string]interface{}{
|
||||
"DB_FriendRequest": fr,
|
||||
"Arg_FriendRequest": friendRequest,
|
||||
})
|
||||
|
||||
// Mark the friend request as refused and update the handle time.
|
||||
friendRequest.HandleResult = constant.FriendResponseRefuse
|
||||
friendRequest.HandleTime = time.Now()
|
||||
err = f.friendRequest.Update(ctx, friendRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := f.friendRequest.Update(ctx, friendRequest); err != nil {
|
||||
return fmt.Errorf("failed to update friend request from %s to %s as refused: %w", friendRequest.FromUserID, friendRequest.ToUserID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略).
|
||||
// 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")
|
||||
@ -227,10 +249,10 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
|
||||
return err
|
||||
}
|
||||
existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string {
|
||||
return [...]string{friend.OwnerUserID, friend.FriendUserID} // 自己 - 好友
|
||||
return [...]string{friend.OwnerUserID, friend.FriendUserID} // My - Friend
|
||||
}))
|
||||
var adds []*relation.FriendModel
|
||||
if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // 自己 - 好友
|
||||
if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // My - Friend
|
||||
adds = append(
|
||||
adds,
|
||||
&relation.FriendModel{
|
||||
@ -241,7 +263,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
|
||||
},
|
||||
)
|
||||
}
|
||||
if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // 好友 - 自己
|
||||
if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // My - Friend
|
||||
adds = append(
|
||||
adds,
|
||||
&relation.FriendModel{
|
||||
@ -261,7 +283,7 @@ func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *
|
||||
})
|
||||
}
|
||||
|
||||
// 删除好友 外部判断是否好友关系.
|
||||
// Delete removes a friend relationship. It is assumed that the external caller has verified the friendship status.
|
||||
func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error) {
|
||||
if err := f.friend.Delete(ctx, ownerUserID, friendUserIDs); err != nil {
|
||||
return err
|
||||
@ -269,7 +291,7 @@ func (f *friendDatabase) Delete(ctx context.Context, ownerUserID string, friendU
|
||||
return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ExecDel(ctx)
|
||||
}
|
||||
|
||||
// 更新好友备注 零值也支持.
|
||||
// UpdateRemark updates the remark for a friend. Zero value for remark is also supported.
|
||||
func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error) {
|
||||
if err := f.friend.UpdateRemark(ctx, ownerUserID, friendUserID, remark); err != nil {
|
||||
return err
|
||||
@ -277,27 +299,27 @@ func (f *friendDatabase) UpdateRemark(ctx context.Context, ownerUserID, friendUs
|
||||
return f.cache.DelFriend(ownerUserID, friendUserID).ExecDel(ctx)
|
||||
}
|
||||
|
||||
// 获取ownerUserID的好友列表 无结果不返回错误.
|
||||
// PageOwnerFriends retrieves the list of friends for the ownerUserID. It does not return an error if the result is empty.
|
||||
func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
|
||||
return f.friend.FindOwnerFriends(ctx, ownerUserID, pagination)
|
||||
}
|
||||
|
||||
// friendUserID在哪些人的好友列表中.
|
||||
// PageInWhoseFriends identifies in whose friend lists the friendUserID appears.
|
||||
func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendModel, err error) {
|
||||
return f.friend.FindInWhoseFriends(ctx, friendUserID, pagination)
|
||||
}
|
||||
|
||||
// 获取我发出去的好友申请 无结果不返回错误.
|
||||
// PageFriendRequestFromMe retrieves friend requests sent by me. It does not return an error if the result is empty.
|
||||
func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
|
||||
return f.friendRequest.FindFromUserID(ctx, userID, pagination)
|
||||
}
|
||||
|
||||
// 获取我收到的的好友申请 无结果不返回错误.
|
||||
// PageFriendRequestToMe retrieves friend requests received by me. It does not return an error if the result is empty.
|
||||
func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, friends []*relation.FriendRequestModel, err error) {
|
||||
return f.friendRequest.FindToUserID(ctx, userID, pagination)
|
||||
}
|
||||
|
||||
// 获取某人指定好友的信息 如果有好友不存在,也返回错误.
|
||||
// FindFriendsWithError retrieves specified friends' information for ownerUserID. Returns an error if any friend does not exist.
|
||||
func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) {
|
||||
friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
|
||||
if err != nil {
|
||||
|
||||
@ -31,47 +31,79 @@ import (
|
||||
)
|
||||
|
||||
type GroupDatabase interface {
|
||||
// Group
|
||||
// CreateGroup creates new groups along with their members.
|
||||
CreateGroup(ctx context.Context, groups []*relationtb.GroupModel, groupMembers []*relationtb.GroupMemberModel) error
|
||||
// TakeGroup retrieves a single group by its ID.
|
||||
TakeGroup(ctx context.Context, groupID string) (group *relationtb.GroupModel, err error)
|
||||
// FindGroup retrieves multiple groups by their IDs.
|
||||
FindGroup(ctx context.Context, groupIDs []string) (groups []*relationtb.GroupModel, err error)
|
||||
// SearchGroup searches for groups based on a keyword and pagination settings, returns total count and groups.
|
||||
SearchGroup(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*relationtb.GroupModel, error)
|
||||
// UpdateGroup updates the properties of a group identified by its ID.
|
||||
UpdateGroup(ctx context.Context, groupID string, data map[string]any) error
|
||||
DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // 解散群,并删除群成员
|
||||
// DismissGroup disbands a group and optionally removes its members based on the deleteMember flag.
|
||||
DismissGroup(ctx context.Context, groupID string, deleteMember bool) error
|
||||
|
||||
// TakeGroupMember retrieves a specific group member by group ID and user ID.
|
||||
TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationtb.GroupMemberModel, err error)
|
||||
// TakeGroupOwner retrieves the owner of a group by group ID.
|
||||
TakeGroupOwner(ctx context.Context, groupID string) (*relationtb.GroupMemberModel, error)
|
||||
FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
|
||||
FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
|
||||
FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error) // *
|
||||
FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error) // *
|
||||
// FindGroupMembers retrieves members of a group filtered by user IDs.
|
||||
FindGroupMembers(ctx context.Context, groupID string, userIDs []string) (groupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// FindGroupMemberUser retrieves groups that a user is a member of, filtered by group IDs.
|
||||
FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) (groupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// FindGroupMemberRoleLevels retrieves group members filtered by their role levels within a group.
|
||||
FindGroupMemberRoleLevels(ctx context.Context, groupID string, roleLevels []int32) (groupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// FindGroupMemberAll retrieves all members of a group.
|
||||
FindGroupMemberAll(ctx context.Context, groupID string) (groupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// FindGroupsOwner retrieves the owners for multiple groups.
|
||||
FindGroupsOwner(ctx context.Context, groupIDs []string) ([]*relationtb.GroupMemberModel, error)
|
||||
// FindGroupMemberUserID retrieves the user IDs of all members in a group.
|
||||
FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error)
|
||||
// FindGroupMemberNum retrieves the number of members in a group.
|
||||
FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error)
|
||||
// FindUserManagedGroupID retrieves group IDs managed by a user.
|
||||
FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error)
|
||||
// PageGroupRequest paginates through group requests for specified groups.
|
||||
PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error)
|
||||
// GetGroupRoleLevelMemberIDs retrieves user IDs of group members with a specific role level.
|
||||
GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error)
|
||||
|
||||
// PageGetJoinGroup paginates through groups that a user has joined.
|
||||
PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// PageGetGroupMember paginates through members of a group.
|
||||
PageGetGroupMember(ctx context.Context, groupID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*relationtb.GroupMemberModel, err error)
|
||||
// SearchGroupMember searches for group members based on a keyword, group ID, and pagination settings.
|
||||
SearchGroupMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*relationtb.GroupMemberModel, error)
|
||||
// HandlerGroupRequest processes a group join request with a specified result.
|
||||
HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationtb.GroupMemberModel) error
|
||||
// DeleteGroupMember removes specified users from a group.
|
||||
DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error
|
||||
// MapGroupMemberUserID maps group IDs to their members' simplified user IDs.
|
||||
MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationtb.GroupSimpleUserID, error)
|
||||
// MapGroupMemberNum maps group IDs to their member count.
|
||||
MapGroupMemberNum(ctx context.Context, groupIDs []string) (map[string]uint32, error)
|
||||
TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error // 转让群
|
||||
// TransferGroupOwner transfers the ownership of a group to another user.
|
||||
TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error
|
||||
// UpdateGroupMember updates properties of a group member.
|
||||
UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error
|
||||
// UpdateGroupMembers batch updates properties of group members.
|
||||
UpdateGroupMembers(ctx context.Context, data []*relationtb.BatchUpdateGroupMember) error
|
||||
// GroupRequest
|
||||
|
||||
// CreateGroupRequest creates new group join requests.
|
||||
CreateGroupRequest(ctx context.Context, requests []*relationtb.GroupRequestModel) error
|
||||
// TakeGroupRequest retrieves a specific group join request.
|
||||
TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationtb.GroupRequestModel, error)
|
||||
// FindGroupRequests retrieves multiple group join requests.
|
||||
FindGroupRequests(ctx context.Context, groupID string, userIDs []string) ([]*relationtb.GroupRequestModel, error)
|
||||
// PageGroupRequestUser paginates through group join requests made by a user.
|
||||
PageGroupRequestUser(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*relationtb.GroupRequestModel, error)
|
||||
|
||||
// 获取群总数
|
||||
// CountTotal counts the total number of groups as of a certain date.
|
||||
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
|
||||
// 获取范围内群增量
|
||||
// CountRangeEverydayTotal counts the daily group creation total within a specified date range.
|
||||
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
|
||||
// DeleteGroupMemberHash deletes the hash entries for group members in specified groups.
|
||||
DeleteGroupMemberHash(ctx context.Context, groupIDs []string) error
|
||||
}
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
}
|
||||
num := db.msg.GetSingleGocMsgNum()
|
||||
// num = 100
|
||||
for i, field := range fields { // 检查类型
|
||||
for i, field := range fields { // Check the type of the field
|
||||
var ok bool
|
||||
switch key {
|
||||
case updateKeyMsg:
|
||||
@ -217,7 +217,7 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
return errs.ErrInternalServer.Wrap("field type is invalid")
|
||||
}
|
||||
}
|
||||
// 返回值为true表示数据库存在该文档,false表示数据库不存在该文档
|
||||
// Returns true if the document exists in the database, false if the document does not exist in the database
|
||||
updateMsgModel := func(seq int64, i int) (bool, error) {
|
||||
var (
|
||||
res *mongo.UpdateResult
|
||||
@ -239,21 +239,21 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
}
|
||||
tryUpdate := true
|
||||
for i := 0; i < len(fields); i++ {
|
||||
seq := firstSeq + int64(i) // 当前seq
|
||||
seq := firstSeq + int64(i) // Current sequence number
|
||||
if tryUpdate {
|
||||
matched, err := updateMsgModel(seq, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if matched {
|
||||
continue // 匹配到了,继续下一个(不一定修改)
|
||||
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),
|
||||
}
|
||||
var insert int // 插入的数量
|
||||
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 {
|
||||
@ -282,14 +282,14 @@ func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationI
|
||||
}
|
||||
if err := db.msgDocDatabase.Create(ctx, &doc); err != nil {
|
||||
if mongo.IsDuplicateKeyError(err) {
|
||||
i-- // 存在并发,重试当前数据
|
||||
tryUpdate = true // 以修改模式
|
||||
i-- // already inserted
|
||||
tryUpdate = true // next block use update mode
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
tryUpdate = false // 当前以插入成功,下一块优先插入模式
|
||||
i += insert - 1 // 跳过已插入的数据
|
||||
tryUpdate = false // The current block is inserted successfully, and the next block is inserted preferentially
|
||||
i += insert - 1 // Skip the inserted data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -753,7 +753,7 @@ func (db *commonMsgDatabase) UserMsgsDestruct(ctx context.Context, userID string
|
||||
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
|
||||
}
|
||||
}
|
||||
// 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归
|
||||
// If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion
|
||||
break
|
||||
}
|
||||
index++
|
||||
@ -808,7 +808,7 @@ func (d *delMsgRecursionStruct) getSetMinSeq() int64 {
|
||||
// index 0....19(del) 20...69
|
||||
// seq 70
|
||||
// set minSeq 21
|
||||
// recursion 删除list并且返回设置的最小seq.
|
||||
// recursion deletes the list and returns the set minimum seq.
|
||||
func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversationID string, index int64, delStruct *delMsgRecursionStruct, remainTime int64) (int64, error) {
|
||||
// find from oldest list
|
||||
msgDocModel, err := db.msgDocDatabase.GetMsgDocModelByIndex(ctx, conversationID, index, 1)
|
||||
@ -820,7 +820,7 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
|
||||
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
|
||||
}
|
||||
}
|
||||
// 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归
|
||||
// If an error is reported, or the error cannot be obtained, it is physically deleted and seq delMongoMsgsPhysical(delStruct.delDocIDList) is returned to end the recursion
|
||||
err = db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@ -58,10 +58,10 @@ func NewAWS() (s3.Interface, error) {
|
||||
credential := credentials.NewStaticCredentials(
|
||||
conf.AccessKeyID, // accessKey
|
||||
conf.AccessKeySecret, // secretKey
|
||||
"") // sts的临时凭证
|
||||
"") // stoken
|
||||
|
||||
sess, err := session.NewSession(&aws.Config{
|
||||
Region: aws.String(conf.Region), // 桶所在的区域
|
||||
Region: aws.String(conf.Region), // The area where the bucket is located
|
||||
Credentials: credential,
|
||||
})
|
||||
|
||||
|
||||
@ -15,10 +15,24 @@
|
||||
package cont
|
||||
|
||||
const (
|
||||
hashPath = "openim/data/hash/"
|
||||
tempPath = "openim/temp/"
|
||||
DirectPath = "openim/direct"
|
||||
UploadTypeMultipart = 1 // 分片上传
|
||||
UploadTypePresigned = 2 // 预签名上传
|
||||
partSeparator = ","
|
||||
// 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 = ","
|
||||
)
|
||||
|
||||
@ -114,7 +114,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64
|
||||
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 {
|
||||
@ -139,7 +139,7 @@ func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
// 分片上传
|
||||
// Fragment upload
|
||||
upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -206,7 +206,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa
|
||||
ETag: part,
|
||||
}
|
||||
}
|
||||
// todo: 验证大小
|
||||
// todo: Validation size
|
||||
result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -225,7 +225,7 @@ func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHa
|
||||
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
|
||||
|
||||
@ -17,9 +17,14 @@ package cont
|
||||
import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
|
||||
|
||||
type InitiateUploadResult struct {
|
||||
UploadID string `json:"uploadID"` // 上传ID
|
||||
PartSize int64 `json:"partSize"` // 分片大小
|
||||
Sign *s3.AuthSignResult `json:"sign"` // 分片信息
|
||||
// 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 {
|
||||
|
||||
@ -42,79 +42,51 @@ func ImageWidthHeight(img image.Image) (int, int) {
|
||||
return bounds.X, bounds.Y
|
||||
}
|
||||
|
||||
// resizeImage resizes an image to a specified maximum width and height, maintaining the aspect ratio.
|
||||
// If both maxWidth and maxHeight are set to 0, the original image is returned.
|
||||
// If both are non-zero, the image is scaled to fit within the constraints while maintaining aspect ratio.
|
||||
// If only one of maxWidth or maxHeight is non-zero, the image is scaled accordingly.
|
||||
func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
|
||||
bounds := img.Bounds()
|
||||
imgWidth := bounds.Max.X
|
||||
imgHeight := bounds.Max.Y
|
||||
imgWidth, imgHeight := bounds.Dx(), bounds.Dy()
|
||||
|
||||
// 计算缩放比例
|
||||
scaleWidth := float64(maxWidth) / float64(imgWidth)
|
||||
scaleHeight := float64(maxHeight) / float64(imgHeight)
|
||||
|
||||
// 如果都为0,则不缩放,返回原始图片
|
||||
// Return original image if no resizing is needed.
|
||||
if maxWidth == 0 && maxHeight == 0 {
|
||||
return img
|
||||
}
|
||||
|
||||
// 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比
|
||||
var scale float64 = 1
|
||||
if maxWidth > 0 && maxHeight > 0 {
|
||||
scale := scaleWidth
|
||||
if scaleHeight < scaleWidth {
|
||||
scale = scaleHeight
|
||||
}
|
||||
|
||||
// 计算缩略图尺寸
|
||||
thumbnailWidth := int(float64(imgWidth) * scale)
|
||||
thumbnailHeight := int(float64(imgHeight) * scale)
|
||||
|
||||
// 使用"image"库的Resample方法生成缩略图
|
||||
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
|
||||
scaleWidth := float64(maxWidth) / float64(imgWidth)
|
||||
scaleHeight := float64(maxHeight) / float64(imgHeight)
|
||||
// Choose the smaller scale to fit both constraints.
|
||||
scale = min(scaleWidth, scaleHeight)
|
||||
} else if maxWidth > 0 {
|
||||
scale = float64(maxWidth) / float64(imgWidth)
|
||||
} else if maxHeight > 0 {
|
||||
scale = float64(maxHeight) / float64(imgHeight)
|
||||
}
|
||||
|
||||
// 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图
|
||||
if maxWidth > 0 {
|
||||
thumbnailWidth := maxWidth
|
||||
thumbnailHeight := int(float64(imgHeight) * scaleWidth)
|
||||
newWidth := int(float64(imgWidth) * scale)
|
||||
newHeight := int(float64(imgHeight) * scale)
|
||||
|
||||
// 使用"image"库的Resample方法生成缩略图
|
||||
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))
|
||||
}
|
||||
// Resize the image by creating a new image and manually copying pixels.
|
||||
thumbnail := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))
|
||||
for y := 0; y < newHeight; y++ {
|
||||
for x := 0; x < newWidth; x++ {
|
||||
srcX := int(float64(x) / scale)
|
||||
srcY := int(float64(y) / scale)
|
||||
thumbnail.Set(x, y, img.At(srcX, srcY))
|
||||
}
|
||||
|
||||
return thumbnail
|
||||
}
|
||||
|
||||
if maxHeight > 0 {
|
||||
thumbnailWidth := int(float64(imgWidth) * scaleHeight)
|
||||
thumbnailHeight := maxHeight
|
||||
|
||||
// 使用"image"库的Resample方法生成缩略图
|
||||
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
|
||||
}
|
||||
|
||||
// 默认情况下,返回原始图片
|
||||
return img
|
||||
return thumbnail
|
||||
}
|
||||
|
||||
// min returns the smaller of x or y.
|
||||
func min(x, y float64) float64 {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
@ -60,7 +61,7 @@ const successCode = http.StatusOK
|
||||
func NewOSS() (s3.Interface, error) {
|
||||
conf := config.Config.Object.Oss
|
||||
if conf.BucketURL == "" {
|
||||
return nil, errors.New("bucket url is empty")
|
||||
return nil, errs.Wrap(errors.New("bucket url is empty"))
|
||||
}
|
||||
client, err := oss.New(conf.Endpoint, conf.AccessKeyID, conf.AccessKeySecret)
|
||||
if err != nil {
|
||||
@ -68,7 +69,7 @@ func NewOSS() (s3.Interface, error) {
|
||||
}
|
||||
bucket, err := client.Bucket(conf.Bucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "ali-oss bucket error")
|
||||
}
|
||||
if conf.BucketURL[len(conf.BucketURL)-1] != '/' {
|
||||
conf.BucketURL += "/"
|
||||
@ -138,10 +139,10 @@ func (o *OSS) CompleteMultipartUpload(ctx context.Context, uploadID string, name
|
||||
|
||||
func (o *OSS) PartSize(ctx context.Context, size int64) (int64, error) {
|
||||
if size <= 0 {
|
||||
return 0, errors.New("size must be greater than 0")
|
||||
return 0, errs.Wrap(errors.New("size must be greater than 0"))
|
||||
}
|
||||
if size > maxPartSize*maxNumSize {
|
||||
return 0, fmt.Errorf("OSS size must be less than the maximum allowed limit")
|
||||
return 0, errs.Wrap(errors.New("size must be less than the maximum allowed limit"))
|
||||
}
|
||||
if size <= minPartSize*maxNumSize {
|
||||
return minPartSize, nil
|
||||
@ -196,25 +197,25 @@ func (o *OSS) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, erro
|
||||
}
|
||||
res := &s3.ObjectInfo{Key: name}
|
||||
if res.ETag = strings.ToLower(strings.ReplaceAll(header.Get("ETag"), `"`, ``)); res.ETag == "" {
|
||||
return nil, errors.New("StatObject etag not found")
|
||||
return nil, errs.Wrap(errors.New("StatObject etag not found"))
|
||||
}
|
||||
if contentLengthStr := 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)
|
||||
return nil, errs.Wrap(err, "StatObject content-length parse error")
|
||||
}
|
||||
if res.Size < 0 {
|
||||
return nil, errors.New("StatObject content-length must be greater than 0")
|
||||
return nil, errs.Wrap(errors.New("StatObject content-length must be greater than 0"))
|
||||
}
|
||||
}
|
||||
if lastModified := header.Get("Last-Modified"); lastModified == "" {
|
||||
return nil, errors.New("StatObject last-modified not found")
|
||||
return nil, errs.Wrap(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 nil, errs.Wrap(err, "StatObject last-modified parse error")
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
@ -227,7 +228,7 @@ func (o *OSS) DeleteObject(ctx context.Context, name string) error {
|
||||
func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) {
|
||||
result, err := o.bucket.CopyObject(src, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "CopyObject error")
|
||||
}
|
||||
return &s3.CopyObjectInfo{
|
||||
Key: dst,
|
||||
@ -261,7 +262,7 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin
|
||||
Bucket: o.bucket.BucketName,
|
||||
}, oss.MaxUploads(100), oss.MaxParts(maxParts), oss.PartNumberMarker(partNumberMarker))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "ListUploadedParts error")
|
||||
}
|
||||
res := &s3.ListUploadedPartsResult{
|
||||
Key: result.Key,
|
||||
@ -286,7 +287,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration,
|
||||
var opts []oss.Option
|
||||
if opt != nil {
|
||||
if opt.Image != nil {
|
||||
// 文档地址: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
|
||||
// Docs Address: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
|
||||
var format string
|
||||
switch opt.Image.Format {
|
||||
case
|
||||
@ -329,7 +330,7 @@ func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration,
|
||||
}
|
||||
rawParams, err := oss.GetRawParams(opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errs.Wrap(err, "AccessURL error")
|
||||
}
|
||||
params := getURLParams(*o.bucket.Client.Conn, rawParams)
|
||||
return getURL(o.um, o.bucket.BucketName, name, params).String(), nil
|
||||
@ -351,12 +352,12 @@ func (o *OSS) FormData(ctx context.Context, name string, size int64, contentType
|
||||
}
|
||||
policyJson, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "Marshal json error")
|
||||
}
|
||||
policyStr := base64.StdEncoding.EncodeToString(policyJson)
|
||||
h := hmac.New(sha1.New, []byte(o.credentials.GetAccessKeySecret()))
|
||||
if _, err := io.WriteString(h, policyStr); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "WriteString error")
|
||||
}
|
||||
fd := &s3.FormData{
|
||||
URL: o.bucketURL,
|
||||
|
||||
@ -651,7 +651,7 @@ func (m *MsgMongoDriver) RangeUserSendCount(
|
||||
"$dateToString": bson.M{
|
||||
"format": "%Y-%m-%d",
|
||||
"date": bson.M{
|
||||
"$toDate": "$$item.msg.send_time", // 毫秒时间戳
|
||||
"$toDate": "$$item.msg.send_time", // Millisecond timestamp
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -900,7 +900,7 @@ func (m *MsgMongoDriver) RangeGroupSendCount(
|
||||
"$dateToString": bson.M{
|
||||
"format": "%Y-%m-%d",
|
||||
"date": bson.M{
|
||||
"$toDate": "$$item.msg.send_time", // 毫秒时间戳
|
||||
"$toDate": "$$item.msg.send_time", // Millisecond timestamp
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -39,7 +39,7 @@ func TestNewDiscoveryRegister(t *testing.T) {
|
||||
expectedResult bool
|
||||
}{
|
||||
{"zookeeper", false, true},
|
||||
{"k8s", false, true}, // 假设 k8s 配置也已正确设置
|
||||
{"k8s", false, true}, // Assume that the k8s configuration is also set up correctly
|
||||
{"direct", false, true},
|
||||
{"invalid", true, false},
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ func NewConversationNotificationSender(msgRpcClient *rpcclient.MessageRpcClient)
|
||||
return &ConversationNotificationSender{rpcclient.NewNotificationSender(rpcclient.WithRpcClient(msgRpcClient))}
|
||||
}
|
||||
|
||||
// SetPrivate调用.
|
||||
// SetPrivate invote
|
||||
func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx context.Context, sendID, recvID string,
|
||||
isPrivateChat bool, conversationID string,
|
||||
) error {
|
||||
@ -45,7 +45,6 @@ func (c *ConversationNotificationSender) ConversationSetPrivateNotification(ctx
|
||||
return c.Notification(ctx, sendID, recvID, constant.ConversationPrivateChatNotification, tips)
|
||||
}
|
||||
|
||||
// 会话改变.
|
||||
func (c *ConversationNotificationSender) ConversationChangeNotification(ctx context.Context, userID string, conversationIDs []string) error {
|
||||
tips := &sdkws.ConversationUpdateTips{
|
||||
UserID: userID,
|
||||
@ -55,7 +54,6 @@ func (c *ConversationNotificationSender) ConversationChangeNotification(ctx cont
|
||||
return c.Notification(ctx, userID, userID, constant.ConversationChangeNotification, tips)
|
||||
}
|
||||
|
||||
// 会话未读数同步.
|
||||
func (c *ConversationNotificationSender) ConversationUnreadChangeNotification(
|
||||
ctx context.Context,
|
||||
userID, conversationID string,
|
||||
|
||||
@ -31,7 +31,7 @@ import (
|
||||
|
||||
type FriendNotificationSender struct {
|
||||
*rpcclient.NotificationSender
|
||||
// 找不到报错
|
||||
// Target not found err
|
||||
getUsersInfo func(ctx context.Context, userIDs []string) ([]CommonUser, error)
|
||||
// db controller
|
||||
db controller.FriendDatabase
|
||||
|
||||
@ -76,7 +76,7 @@ func TestCopyFlags(t *testing.T) {
|
||||
}()
|
||||
CopyFlags(tt.args.source, tt.args.target)
|
||||
|
||||
// 验证复制的标记
|
||||
// Verify the replicated tag
|
||||
if !tt.wantErr {
|
||||
tt.args.source.VisitAll(func(f *flag.Flag) {
|
||||
if gotFlag := tt.args.target.Lookup(f.Name); gotFlag == nil || !reflect.DeepEqual(gotFlag, f) {
|
||||
|
||||
@ -28,20 +28,20 @@ import (
|
||||
|
||||
func main() {
|
||||
var (
|
||||
usernameV2 = "root" // v2版本mysql用户名
|
||||
passwordV2 = "openIM" // v2版本mysql密码
|
||||
addrV2 = "127.0.0.1:13306" // v2版本mysql地址
|
||||
databaseV2 = "admin_chat" // v2版本mysql数据库名字
|
||||
usernameV2 = "root" // Username for MySQL v2 version
|
||||
passwordV2 = "openIM" // Password for MySQL v2 version
|
||||
addrV2 = "127.0.0.1:13306" // Address for MySQL v2 version
|
||||
databaseV2 = "admin_chat" // Database name for MySQL v2 version
|
||||
)
|
||||
|
||||
var (
|
||||
usernameV3 = "root" // v3版本mysql用户名
|
||||
passwordV3 = "openIM123" // v3版本mysql密码
|
||||
addrV3 = "127.0.0.1:13306" // v3版本mysql地址
|
||||
databaseV3 = "openim_enterprise" // v3版本mysql数据库名字
|
||||
usernameV3 = "root" // Username for MySQL v3 version
|
||||
passwordV3 = "openIM123" // Password for MySQL v3 version
|
||||
addrV3 = "127.0.0.1:13306" // Address for MySQL v3 version
|
||||
databaseV3 = "openim_enterprise" // Database name for MySQL v3 version
|
||||
)
|
||||
|
||||
var concurrency = 1 // 并发数量
|
||||
var concurrency = 1 // Concurrency quantity
|
||||
|
||||
log.SetFlags(log.LstdFlags | log.Llongfile)
|
||||
dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2)
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// AppVersion pc端版本管理
|
||||
// AppVersion manages PC client versions
|
||||
type AppVersion struct {
|
||||
Version string `gorm:"column:version;size:64" json:"version"`
|
||||
Type int `gorm:"column:type;primary_key" json:"type"`
|
||||
@ -29,7 +29,7 @@ type AppVersion struct {
|
||||
UpdateLog string `gorm:"column:update_log" json:"update_log"`
|
||||
}
|
||||
|
||||
// Admin 后台管理员
|
||||
// Admin manages backend administrators
|
||||
type Admin struct {
|
||||
Account string `gorm:"column:account;primary_key;type:char(64)" json:"account"`
|
||||
Password string `gorm:"column:Password;type:char(64)" json:"password"`
|
||||
@ -40,19 +40,19 @@ type Admin struct {
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// RegisterAddFriend 注册时默认好友
|
||||
// RegisterAddFriend specifies default friends when registering
|
||||
type RegisterAddFriend struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// RegisterAddGroup 注册时默认群组
|
||||
// RegisterAddGroup specifies default groups when registering
|
||||
type RegisterAddGroup struct {
|
||||
GroupID string `gorm:"column:group_id;primary_key;type:char(64)" json:"userID"`
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// ClientInitConfig 系统相关配置项
|
||||
// ClientInitConfig contains system-related configuration items
|
||||
type ClientInitConfig struct {
|
||||
DiscoverPageURL string `gorm:"column:discover_page_url;size:128" json:"discoverPageURL"`
|
||||
OrdinaryUserAddFriend int32 `gorm:"column:ordinary_user_add_friend; default:1" json:"ordinaryUserAddFriend"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Register 注册信息表
|
||||
// Register Registration information sheet
|
||||
type Register struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
||||
DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"`
|
||||
@ -29,7 +29,7 @@ type Register struct {
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// Account 账号密码表
|
||||
// Account username and password table
|
||||
type Account struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
||||
Password string `gorm:"column:password;type:varchar(255)" json:"password"`
|
||||
@ -38,7 +38,7 @@ type Account struct {
|
||||
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)" json:"operatorUserID"`
|
||||
}
|
||||
|
||||
// Attribute 用户属性表
|
||||
// Attribute user information table
|
||||
type Attribute struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
||||
Account string `gorm:"column:account;type:char(64)" json:"account"`
|
||||
@ -58,7 +58,7 @@ type Attribute struct {
|
||||
AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1" json:"allowAddFriend"`
|
||||
}
|
||||
|
||||
// 封号表
|
||||
// User friend relationship table
|
||||
type ForbiddenAccount struct {
|
||||
UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)" json:"userID"`
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
@ -66,7 +66,7 @@ type ForbiddenAccount struct {
|
||||
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)" json:"operatorUserID"`
|
||||
}
|
||||
|
||||
// 用户登录信息表
|
||||
// user login record table
|
||||
type UserLoginRecord struct {
|
||||
UserID string `gorm:"column:user_id;size:64" json:"userID"`
|
||||
LoginTime time.Time `gorm:"column:login_time" json:"loginTime"`
|
||||
@ -75,7 +75,7 @@ type UserLoginRecord struct {
|
||||
Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"`
|
||||
}
|
||||
|
||||
// 禁止ip登录 注册
|
||||
// ip login registration is prohibited
|
||||
type IPForbidden struct {
|
||||
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
|
||||
LimitRegister int32 `gorm:"column:limit_register" json:"limitRegister"`
|
||||
@ -83,14 +83,14 @@ type IPForbidden struct {
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// 限制userID只能在某些ip登录
|
||||
// Restrict userids to certain ip addresses
|
||||
type LimitUserLoginIP struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
||||
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
}
|
||||
|
||||
// 邀请码被注册使用
|
||||
// The invitation code is registered for use
|
||||
type InvitationRegister struct {
|
||||
InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)" json:"invitationCode"`
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Admin 后台管理员.
|
||||
// Admin Background administrator.
|
||||
type Admin struct {
|
||||
Account string `gorm:"column:account;primary_key;type:varchar(64)"`
|
||||
Password string `gorm:"column:password;type:varchar(64)"`
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
package admin
|
||||
|
||||
// ClientConfig 客户端相关配置项.
|
||||
// ClientConfig Client related configuration items.
|
||||
type ClientConfig struct {
|
||||
Key string `gorm:"column:key;primary_key;type:varchar(255)"`
|
||||
Value string `gorm:"column:value;not null;type:text"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ForbiddenAccount 封号表.
|
||||
// ForbiddenAccount forbidden account.
|
||||
type ForbiddenAccount struct {
|
||||
UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)"`
|
||||
Reason string `gorm:"column:reason;type:varchar(255)" `
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 邀请码被注册使用.
|
||||
// The invitation code is registered for use.
|
||||
type InvitationRegister struct {
|
||||
InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)"`
|
||||
UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 禁止ip登录 注册.
|
||||
// ip login registration is prohibited.
|
||||
type IPForbidden struct {
|
||||
IP string `gorm:"column:ip;primary_key;type:char(32)"`
|
||||
LimitRegister bool `gorm:"column:limit_register"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 限制userID只能在某些ip登录.
|
||||
// Restrict userids to certain ip addresses.
|
||||
type LimitUserLoginIP struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
|
||||
IP string `gorm:"column:ip;primary_key;type:char(32)"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RegisterAddFriend 注册时默认好友.
|
||||
// RegisterAddFriend Indicates the default friend when registering.
|
||||
type RegisterAddFriend struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RegisterAddGroup 注册时默认群组.
|
||||
// RegisterAddGroup Indicates the default group for registration.
|
||||
type RegisterAddGroup struct {
|
||||
GroupID string `gorm:"column:group_id;primary_key;type:char(64)"`
|
||||
CreateTime time.Time `gorm:"column:create_time"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Account 账号密码表.
|
||||
// Account Account password table.
|
||||
type Account struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
|
||||
Password string `gorm:"column:password;type:varchar(32)"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Attribute 用户属性表.
|
||||
// Attribute Indicates the user attribute table.
|
||||
type Attribute struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
|
||||
Account string `gorm:"column:account;type:char(64)"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Register 注册信息表.
|
||||
// Register Indicates the registration information.
|
||||
type Register struct {
|
||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)"`
|
||||
DeviceID string `gorm:"column:device_id;type:varchar(255)"`
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 用户登录信息表.
|
||||
// User login information table.
|
||||
type UserLoginRecord struct {
|
||||
UserID string `gorm:"column:user_id;size:64"`
|
||||
LoginTime time.Time `gorm:"column:login_time"`
|
||||
|
||||
@ -38,11 +38,20 @@ import (
|
||||
func main() {
|
||||
|
||||
var (
|
||||
topic = "ws2ms_chat" // v2版本配置文件kafka.topic.ws2ms_chat
|
||||
kafkaAddr = "127.0.0.1:9092" // v2版本配置文件kafka.topic.addr
|
||||
rpcAddr = "127.0.0.1:10130" // v3版本配置文件rpcPort.openImMessagePort
|
||||
adminUserID = "openIM123456" // v3版本管理员userID
|
||||
concurrency = 1 // 并发数量
|
||||
// The Kafka topic for ws2ms_chat in version 2 configuration
|
||||
topic = "ws2ms_chat"
|
||||
|
||||
// The Kafka address in version 2 configuration
|
||||
kafkaAddr = "127.0.0.1:9092"
|
||||
|
||||
// The RPC address in version 3 configuration
|
||||
rpcAddr = "127.0.0.1:10130"
|
||||
|
||||
// The administrator userID in version 3
|
||||
adminUserID = "openIM123456"
|
||||
|
||||
// The number of concurrent processes
|
||||
concurrency = 1
|
||||
)
|
||||
|
||||
getRpcConn := func() (*grpc.ClientConn, error) {
|
||||
@ -99,7 +108,7 @@ func main() {
|
||||
ch := pc.Messages()
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10): // 10s读取不到就关闭
|
||||
case <-time.After(time.Second * 10): // 10s Shuts down when the data cannot be read
|
||||
return
|
||||
case message, ok := <-ch:
|
||||
if !ok {
|
||||
|
||||
@ -27,21 +27,37 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
var (
|
||||
usernameV2 = "root" // v2版本mysql用户名
|
||||
passwordV2 = "openIM" // v2版本mysql密码
|
||||
addrV2 = "127.0.0.1:13306" // v2版本mysql地址
|
||||
databaseV2 = "openIM_v2" // v2版本mysql数据库名字
|
||||
// MySQL username for version 2
|
||||
usernameV2 = "root"
|
||||
|
||||
// MySQL password for version 2
|
||||
passwordV2 = "openIM"
|
||||
|
||||
// MySQL address for version 2
|
||||
addrV2 = "127.0.0.1:13306"
|
||||
|
||||
// MySQL database name for version 2
|
||||
databaseV2 = "openIM_v2"
|
||||
)
|
||||
|
||||
var (
|
||||
usernameV3 = "root" // v3版本mysql用户名
|
||||
passwordV3 = "openIM123" // v3版本mysql密码
|
||||
addrV3 = "127.0.0.1:13306" // v3版本mysql地址
|
||||
databaseV3 = "openim_v3" // v3版本mysql数据库名字
|
||||
// MySQL username for version 3
|
||||
usernameV3 = "root"
|
||||
|
||||
// MySQL password for version 3
|
||||
passwordV3 = "openIM123"
|
||||
|
||||
// MySQL address for version 3
|
||||
addrV3 = "127.0.0.1:13306"
|
||||
|
||||
// MySQL database name for version 3
|
||||
databaseV3 = "openim_v3"
|
||||
)
|
||||
|
||||
var concurrency = 1 // 并发数量
|
||||
// The number of concurrent processes
|
||||
var concurrency = 1
|
||||
|
||||
log.SetFlags(log.LstdFlags | log.Llongfile)
|
||||
dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2)
|
||||
|
||||
@ -38,41 +38,30 @@ func (FriendModel) TableName() string {
|
||||
}
|
||||
|
||||
type FriendModelInterface interface {
|
||||
// 插入多条记录
|
||||
Create(ctx context.Context, friends []*FriendModel) (err error)
|
||||
// 删除ownerUserID指定的好友
|
||||
Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error)
|
||||
// 更新ownerUserID单个好友信息 更新零值
|
||||
UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) (err error)
|
||||
// 更新好友信息的非零值
|
||||
Update(ctx context.Context, friends []*FriendModel) (err error)
|
||||
// 更新好友备注(也支持零值 )
|
||||
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
|
||||
// 获取单个好友信息,如没找到 返回错误
|
||||
Take(ctx context.Context, ownerUserID, friendUserID string) (friend *FriendModel, err error)
|
||||
// 查找好友关系,如果是双向关系,则都返回
|
||||
FindUserState(ctx context.Context, userID1, userID2 string) (friends []*FriendModel, err error)
|
||||
// 获取 owner指定的好友列表 如果有friendUserIDs不存在,也不返回错误
|
||||
FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*FriendModel, err error)
|
||||
// 获取哪些人添加了friendUserID 如果有ownerUserIDs不存在,也不返回错误
|
||||
FindReversalFriends(
|
||||
ctx context.Context,
|
||||
friendUserID string,
|
||||
ownerUserIDs []string,
|
||||
) (friends []*FriendModel, err error)
|
||||
// 获取ownerUserID好友列表 支持翻页
|
||||
FindOwnerFriends(
|
||||
ctx context.Context,
|
||||
ownerUserID string,
|
||||
pageNumber, showNumber int32,
|
||||
) (friends []*FriendModel, total int64, err error)
|
||||
// 获取哪些人添加了friendUserID 支持翻页
|
||||
FindInWhoseFriends(
|
||||
ctx context.Context,
|
||||
friendUserID string,
|
||||
pageNumber, showNumber int32,
|
||||
) (friends []*FriendModel, total int64, err error)
|
||||
// 获取好友UserID列表
|
||||
FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
|
||||
// Create inserts multiple friend records.
|
||||
Create(ctx context.Context, friends []*FriendModel) error
|
||||
// Delete removes specified friends for an owner user.
|
||||
Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) error
|
||||
// UpdateByMap updates a single friend's information for an owner user based on a map of arguments. Zero values are updated.
|
||||
UpdateByMap(ctx context.Context, ownerUserID string, friendUserID string, args map[string]interface{}) error
|
||||
// Update modifies the information of friends, excluding zero values.
|
||||
Update(ctx context.Context, friends []*FriendModel) error
|
||||
// UpdateRemark updates the remark for a friend, supporting zero values.
|
||||
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) error
|
||||
// Take retrieves a single friend's information. Returns an error if not found.
|
||||
Take(ctx context.Context, ownerUserID, friendUserID string) (*FriendModel, error)
|
||||
// FindUserState finds the friendship status between two users, returning both if a mutual friendship exists.
|
||||
FindUserState(ctx context.Context, userID1, userID2 string) ([]*FriendModel, error)
|
||||
// FindFriends retrieves a list of friends for an owner, not returning an error for non-existent friendUserIDs.
|
||||
FindFriends(ctx context.Context, ownerUserID string, friendUserIDs []string) ([]*FriendModel, error)
|
||||
// FindReversalFriends finds who has added the specified user as a friend, not returning an error for non-existent ownerUserIDs.
|
||||
FindReversalFriends(ctx context.Context, friendUserID string, ownerUserIDs []string) ([]*FriendModel, error)
|
||||
// FindOwnerFriends paginates through the friends list of an owner user.
|
||||
FindOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error)
|
||||
// FindInWhoseFriends paginates through users who have added the specified user as a friend.
|
||||
FindInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) ([]*FriendModel, int64, error)
|
||||
// FindFriendUserIDs retrieves a list of friend user IDs for an owner user.
|
||||
FindFriendUserIDs(ctx context.Context, ownerUserID string) ([]string, error)
|
||||
// NewTx creates a new transactional instance of the FriendModelInterface.
|
||||
NewTx(tx any) FriendModelInterface
|
||||
}
|
||||
|
||||
@ -58,9 +58,10 @@ type GroupModelInterface interface {
|
||||
keyword string,
|
||||
pageNumber, showNumber int32,
|
||||
) (total uint32, groups []*GroupModel, err error)
|
||||
// GetGroupIDsByCreatorUserID retrieves a list of group IDs created by the specified user.
|
||||
GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error)
|
||||
// 获取群总数
|
||||
// CountTotal retrieves the total number of groups.
|
||||
CountTotal(ctx context.Context, before *time.Time) (count int64, err error)
|
||||
// 获取范围内群增量
|
||||
// CountRangeEverydayTotal retrieves the total number of groups created every day within the specified time range.
|
||||
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ import (
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// 定义一个函数以打印重要的链接信息
|
||||
// Define a function to print important link information
|
||||
func printLinks() {
|
||||
blue := color.New(color.FgBlue).SprintFunc()
|
||||
fmt.Printf("OpenIM Github: %s\n", blue("https://github.com/OpenIMSDK/Open-IM-Server"))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user