feat: use robot to migrate code

Signed-off-by: kubbot & kubecub <3293172751ysy@gmail.com>
This commit is contained in:
kubbot & kubecub
2023-06-30 09:45:02 +08:00
parent 2d41819008
commit 539e0fdfb6
529 changed files with 64588 additions and 54413 deletions
+14
View File
@@ -0,0 +1,14 @@
package apiresp
import (
"github.com/gin-gonic/gin"
"net/http"
)
func GinError(c *gin.Context, err error) {
c.JSON(http.StatusOK, ParseError(err))
}
func GinSuccess(c *gin.Context, data any) {
c.JSON(http.StatusOK, ApiSuccess(data))
}
+25
View File
@@ -0,0 +1,25 @@
package apiresp
import (
"encoding/json"
"net/http"
)
func httpJson(w http.ResponseWriter, data any) {
body, err := json.Marshal(data)
if err != nil {
http.Error(w, "json marshal error: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(body)
}
func HttpError(w http.ResponseWriter, err error) {
httpJson(w, ParseError(err))
}
func HttpSuccess(w http.ResponseWriter, data any) {
httpJson(w, ApiSuccess(data))
}
+58
View File
@@ -0,0 +1,58 @@
package apiresp
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"reflect"
)
type ApiResponse struct {
ErrCode int `json:"errCode"`
ErrMsg string `json:"errMsg"`
ErrDlt string `json:"errDlt"`
Data any `json:"data,omitempty"`
}
func isAllFieldsPrivate(v any) bool {
typeOf := reflect.TypeOf(v)
if typeOf == nil {
return false
}
if typeOf.Kind() == reflect.Ptr {
typeOf = typeOf.Elem()
}
if typeOf.Kind() != reflect.Struct {
return false
}
num := typeOf.NumField()
for i := 0; i < num; i++ {
c := typeOf.Field(i).Name[0]
if c >= 'A' && c <= 'Z' {
return false
}
}
return true
}
func ApiSuccess(data any) *ApiResponse {
if isAllFieldsPrivate(data) {
return &ApiResponse{}
}
return &ApiResponse{
Data: data,
}
}
func ParseError(err error) *ApiResponse {
if err == nil {
return ApiSuccess(nil)
}
unwrap := errs.Unwrap(err)
if codeErr, ok := unwrap.(errs.CodeError); ok {
resp := ApiResponse{ErrCode: codeErr.Code(), ErrMsg: codeErr.Msg(), ErrDlt: codeErr.Detail()}
if resp.ErrDlt == "" {
resp.ErrDlt = err.Error()
}
return &resp
}
return &ApiResponse{ErrCode: errs.ServerInternalError, ErrMsg: err.Error()}
}
+55
View File
@@ -0,0 +1,55 @@
package apistruct
type UserRegisterReq struct {
Secret string `json:"secret" binding:"required,max=32"`
Platform int32 `json:"platform" binding:"required,min=1,max=12"`
ApiUserInfo
OperationID string `json:"operationID" binding:"required"`
}
type UserTokenInfo struct {
UserID string `json:"userID"`
Token string `json:"token"`
ExpiredTime int64 `json:"expiredTime"`
}
type UserRegisterResp struct {
UserToken UserTokenInfo `json:"data"`
}
type UserTokenReq struct {
Secret string `json:"secret" binding:"required,max=32"`
Platform int32 `json:"platform" binding:"required,min=1,max=12"`
UserID string `json:"userID" binding:"required,min=1,max=64"`
OperationID string `json:"operationID" binding:"required"`
}
type UserTokenResp struct {
UserToken UserTokenInfo `json:"data"`
}
type ForceLogoutReq struct {
Platform int32 `json:"platform" binding:"required,min=1,max=12"`
FromUserID string `json:"fromUserID" binding:"required,min=1,max=64"`
OperationID string `json:"operationID" binding:"required"`
}
type ForceLogoutResp struct {
}
type ParseTokenReq struct {
OperationID string `json:"operationID" binding:"required"`
}
//type ParseTokenResp struct {
//
// ExpireTime int64 `json:"expireTime" binding:"required"`
//}
type ExpireTime struct {
ExpireTimeSeconds uint32 `json:"expireTimeSeconds" `
}
type ParseTokenResp struct {
Data map[string]interface{} `json:"data" swaggerignore:"true"`
ExpireTime ExpireTime `json:"-"`
}
+19
View File
@@ -0,0 +1,19 @@
package apistruct
type AwsStorageCredentialReq struct {
OperationID string `json:"operationID"`
}
type AwsStorageCredentialRespData struct {
AccessKeyId string `json:"accessKeyID"`
SecretAccessKey string `json:"secretAccessKey"`
SessionToken string `json:"sessionToken"`
RegionID string `json:"regionId"`
Bucket string `json:"bucket"`
FinalHost string `json:"FinalHost"`
}
type AwsStorageCredentialResp struct {
CosData AwsStorageCredentialRespData
Data map[string]interface{} `json:"data"`
}
@@ -1,4 +1,4 @@
package base_info
package apistruct
type OptResult struct {
ConversationID string `json:"conversationID"`
@@ -9,7 +9,6 @@ type GetAllConversationMessageOptReq struct {
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetAllConversationMessageOptResp struct {
CommResp
ConversationOptResultList []*OptResult `json:"data"`
}
type GetReceiveMessageOptReq struct {
@@ -18,7 +17,6 @@ type GetReceiveMessageOptReq struct {
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetReceiveMessageOptResp struct {
CommResp
ConversationOptResultList []*OptResult `json:"data"`
}
type SetReceiveMessageOptReq struct {
@@ -28,7 +26,6 @@ type SetReceiveMessageOptReq struct {
ConversationIDList []string `json:"conversationIDList" binding:"required"`
}
type SetReceiveMessageOptResp struct {
CommResp
ConversationOptResultList []*OptResult `json:"data"`
}
@@ -43,9 +40,10 @@ type Conversation struct {
DraftTextTime int64 `json:"draftTextTime"`
IsPinned bool `json:"isPinned" binding:"omitempty"`
IsPrivateChat bool `json:"isPrivateChat"`
BurnDuration int32 `json:"burnDuration"`
GroupAtType int32 `json:"groupAtType"`
UpdateUnreadCountTime int64 `json:"updateUnreadCountTime"`
IsNotInGroup bool `json:"isNotInGroup"`
UpdateUnreadCountTime int64 `json:"updateUnreadCountTime"`
AttachedInfo string `json:"attachedInfo"`
Ex string `json:"ex"`
}
@@ -57,7 +55,6 @@ type SetConversationReq struct {
}
type SetConversationResp struct {
CommResp
}
type ModifyConversationFieldReq struct {
Conversation
@@ -66,7 +63,6 @@ type ModifyConversationFieldReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type ModifyConversationFieldResp struct {
CommResp
}
type BatchSetConversationsReq struct {
@@ -77,7 +73,6 @@ type BatchSetConversationsReq struct {
}
type BatchSetConversationsResp struct {
CommResp
Data struct {
Success []string `json:"success"`
Failed []string `json:"failed"`
@@ -91,7 +86,6 @@ type GetConversationReq struct {
}
type GetConversationResp struct {
CommResp
Conversation Conversation `json:"data"`
}
@@ -101,7 +95,6 @@ type GetAllConversationsReq struct {
}
type GetAllConversationsResp struct {
CommResp
Conversations []Conversation `json:"data"`
}
@@ -112,7 +105,6 @@ type GetConversationsReq struct {
}
type GetConversationsResp struct {
CommResp
Conversations []Conversation `json:"data"`
}
@@ -125,5 +117,4 @@ type SetRecvMsgOptReq struct {
}
type SetRecvMsgOptResp struct {
CommResp
}
@@ -1,4 +1,4 @@
package base_info
package apistruct
import sts "github.com/tencentyun/qcloud-cos-sts-sdk/go"
@@ -13,7 +13,6 @@ type TencentCloudStorageCredentialRespData struct {
}
type TencentCloudStorageCredentialResp struct {
CommResp
CosData TencentCloudStorageCredentialRespData `json:"-"`
Data map[string]interface{} `json:"data"`
+273
View File
@@ -0,0 +1,273 @@
package apistruct
//type ParamsCommFriend struct {
// OperationID string `json:"operationID" binding:"required"`
// ToUserID string `json:"toUserID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//
//type AddBlacklistReq struct {
// ParamsCommFriend
//}
//type AddBlacklistResp struct {
//
//}
//
//type ImportFriendReq struct {
// FriendUserIDList []string `json:"friendUserIDList" binding:"required"`
// OperationID string `json:"operationID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//type UserIDResult struct {
// UserID string `json:"userID"`
// Result int32 `json:"result"`
//}
//type ImportFriendResp struct {
//
// UserIDResultList []UserIDResult `json:"data"`
//}
//
//type AddFriendReq struct {
// ParamsCommFriend
// ReqMsg string `json:"reqMsg"`
//}
//type AddFriendResp struct {
//
//}
//
//type AddFriendResponseReq struct {
// ParamsCommFriend
// Flag int32 `json:"flag" binding:"required,oneof=-1 0 1"`
// HandleMsg string `json:"handleMsg"`
//}
//type AddFriendResponseResp struct {
//
//}
//
//type DeleteFriendReq struct {
// ParamsCommFriend
//}
//type DeleteFriendResp struct {
//
//}
//
//type GetBlackListReq struct {
// OperationID string `json:"operationID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//type GetBlackListResp struct {
//
// BlackUserInfoList []*sdkws.PublicUserInfo `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
//
////type PublicUserInfo struct {
//// UserID string `json:"userID"`
//// Nickname string `json:"nickname"`
//// FaceUrl string `json:"faceUrl"`
//// Gender int32 `json:"gender"`
////}
//
//type SetFriendRemarkReq struct {
// ParamsCommFriend
// Remark string `json:"remark"`
//}
//type SetFriendRemarkResp struct {
//
//}
//
//type RemoveBlacklistReq struct {
// ParamsCommFriend
//}
//type RemoveBlacklistResp struct {
//
//}
//
//type IsFriendReq struct {
// ParamsCommFriend
//}
//type Response struct {
// Friend bool `json:"isFriend"`
//}
//type IsFriendResp struct {
//
// Response Response `json:"data"`
//}
//
//type GetFriendsInfoReq struct {
// ParamsCommFriend
//}
//type GetFriendsInfoResp struct {
//
// FriendInfoList []*sdkws.FriendInfo `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
//
//type GetFriendListReq struct {
// OperationID string `json:"operationID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//type GetFriendListResp struct {
//
// FriendInfoList []*sdkws.FriendInfo `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
//
//type GetFriendApplyListReq struct {
// OperationID string `json:"operationID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//type GetFriendApplyListResp struct {
//
// FriendRequestList []*sdkws.FriendRequest `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
//
//type GetSelfApplyListReq struct {
// OperationID string `json:"operationID" binding:"required"`
// FromUserID string `json:"fromUserID" binding:"required"`
//}
//type GetSelfApplyListResp struct {
//
// FriendRequestList []*sdkws.FriendRequest `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
type FriendInfo struct {
UserID string `json:"userID"`
Nickname string `json:"nickname"`
FaceURL string `json:"faceURL"`
Gender int32 `json:"gender"`
Ex string `json:"ex"`
}
type PublicUserInfo struct {
UserID string `json:"userID"`
Nickname string `json:"nickname"`
FaceURL string `json:"faceURL"`
Gender int32 `json:"gender"`
Ex string `json:"ex"`
}
type FriendRequest struct {
FromUserID string `json:"fromUserID"`
FromNickname string `json:"fromNickname"`
FromFaceURL string `json:"fromFaceURL"`
FromGender int32 `json:"fromGender"`
ToUserID string `json:"toUserID"`
ToNickname string `json:"toNickname"`
ToFaceURL string `json:"toFaceURL"`
ToGender int32 `json:"toGender"`
HandleResult int32 `json:"handleResult"`
ReqMsg string `json:"reqMsg"`
CreateTime uint32 `json:"createTime"`
HandlerUserID string `json:"handlerUserID"`
HandleMsg string `json:"handleMsg"`
HandleTime uint32 `json:"handleTime"`
Ex string `json:"ex"`
}
type AddBlacklistReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type AddBlacklistResp struct {
}
type ImportFriendReq struct {
FriendUserIDList []string `json:"friendUserIDList" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type ImportFriendResp struct {
//
}
type AddFriendReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
ReqMsg string `json:"reqMsg"`
}
type AddFriendResp struct {
//
}
type AddFriendResponseReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
HandleResult int32 `json:"flag" binding:"required,oneof=-1 0 1"`
HandleMsg string `json:"handleMsg"`
}
type AddFriendResponseResp struct {
}
type DeleteFriendReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type DeleteFriendResp struct {
}
type GetBlackListReq struct {
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetBlackListResp struct {
BlackUserInfoList []PublicUserInfo `json:"blackUserInfoList"`
}
type SetFriendRemarkReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
Remark string `json:"remark"`
}
type SetFriendRemarkResp struct {
}
type RemoveBlacklistReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type RemoveBlacklistResp struct {
}
type IsFriendReq struct {
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type Response struct {
Friend bool `json:"isFriend"`
}
type IsFriendResp struct {
Response Response `json:"data"`
}
type GetFriendListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetFriendListResp struct {
OwnerUserID string `json:"ownerUserID"`
Remark string `json:"remark"`
CreateTime uint32 `json:"createTime"`
AddSource int32 `json:"addSource"`
OperatorUserID string `json:"operatorUserID"`
Ex string `json:"ex"`
//FriendUser *UserInfo // TODO
}
type GetFriendApplyListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetFriendApplyListResp struct {
FriendRequestList []FriendRequest `json:"friendRequestList"`
}
type GetSelfApplyListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetSelfApplyListResp struct {
FriendRequestList []FriendRequest `json:"friendRequestList"`
}
@@ -1,19 +1,9 @@
package base_info
package apistruct
import (
open_im_sdk "Open_IM/pkg/proto/sdk_ws"
sdkws "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
type CommResp struct {
ErrCode int32 `json:"errCode"`
ErrMsg string `json:"errMsg"`
}
type CommDataResp struct {
CommResp
Data []map[string]interface{} `json:"data"`
}
type KickGroupMemberReq struct {
GroupID string `json:"groupID" binding:"required"`
KickedUserIDList []string `json:"kickedUserIDList" binding:"required"`
@@ -21,8 +11,8 @@ type KickGroupMemberReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type KickGroupMemberResp struct {
CommResp
UserIDResultList []*UserIDResult `json:"data"`
//UserIDResultList []*UserIDResult `json:"data"`
}
type GetGroupMembersInfoReq struct {
@@ -31,9 +21,8 @@ type GetGroupMembersInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetGroupMembersInfoResp struct {
CommResp
MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
MemberList []*sdkws.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
type InviteUserToGroupReq struct {
@@ -43,8 +32,8 @@ type InviteUserToGroupReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type InviteUserToGroupResp struct {
CommResp
UserIDResultList []*UserIDResult `json:"data"`
//UserIDResultList []*UserIDResult `json:"data"`
}
type GetJoinedGroupListReq struct {
@@ -52,9 +41,8 @@ type GetJoinedGroupListReq struct {
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetJoinedGroupListResp struct {
CommResp
GroupInfoList []*open_im_sdk.GroupInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
GroupInfoList []*sdkws.GroupInfo `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
type GetGroupMemberListReq struct {
@@ -64,25 +52,38 @@ type GetGroupMemberListReq struct {
OperationID string `json:"operationID"`
}
type GetGroupMemberListResp struct {
CommResp
NextSeq int32 `json:"nextSeq"`
MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
NextSeq int32 `json:"nextSeq"`
MemberList []*sdkws.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
type GetGroupAllMemberReq struct {
GroupID string `json:"groupID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
Offset int32 `json:"offset"`
Count int32 `json:"count"`
}
type GetGroupAllMemberResp struct {
CommResp
MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
MemberList []*sdkws.GroupMemberFullInfo `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
//
//type GetGroupAllMemberListBySplitReq struct {
// GroupID string `json:"groupID" binding:"required"`
// OperationID string `json:"operationID" binding:"required"`
// Offset int32 `json:"offset" binding:"required"`
// Count int32 `json:"count" binding:"required"`
//}
//type GetGroupAllMemberListBySplitResp struct {
//
// MemberList []*sdkws.GroupMemberFullInfo `json:"-"`
// Map []map[string]interface{} `json:"data" swaggerignore:"true"`
//}
type CreateGroupReq struct {
MemberList []*GroupAddMemberInfo `json:"memberList" binding:"required"`
OwnerUserID string `json:"ownerUserID" binding:"required"`
MemberList []*GroupAddMemberInfo `json:"memberList"`
OwnerUserID string `json:"ownerUserID"`
GroupType int32 `json:"groupType"`
GroupName string `json:"groupName"`
Notification string `json:"notification"`
@@ -90,11 +91,11 @@ type CreateGroupReq struct {
FaceURL string `json:"faceURL"`
Ex string `json:"ex"`
OperationID string `json:"operationID" binding:"required"`
GroupID string `json:"groupID"`
}
type CreateGroupResp struct {
CommResp
GroupInfo open_im_sdk.GroupInfo `json:"-"`
Data map[string]interface{} `json:"data"`
GroupInfo sdkws.GroupInfo `json:"-"`
Data map[string]interface{} `json:"data" swaggerignore:"true"`
}
type GetGroupApplicationListReq struct {
@@ -102,9 +103,8 @@ type GetGroupApplicationListReq struct {
FromUserID string `json:"fromUserID" binding:"required"` //作为管理员或群主收到的 进群申请
}
type GetGroupApplicationListResp struct {
CommResp
GroupRequestList []*open_im_sdk.GroupRequest `json:"-"`
Data []map[string]interface{} `json:"data"`
GroupRequestList []*sdkws.GroupRequest `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
type GetUserReqGroupApplicationListReq struct {
@@ -113,8 +113,7 @@ type GetUserReqGroupApplicationListReq struct {
}
type GetUserRespGroupApplicationResp struct {
CommResp
GroupRequestList []*open_im_sdk.GroupRequest `json:"-"`
GroupRequestList []*sdkws.GroupRequest `json:"data"`
}
type GetGroupInfoReq struct {
@@ -122,13 +121,12 @@ type GetGroupInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetGroupInfoResp struct {
CommResp
GroupInfoList []*open_im_sdk.GroupInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
GroupInfoList []*sdkws.GroupInfo `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
//type GroupInfoAlias struct {
// open_im_sdk.GroupInfo
// sdkws.GroupInfo
// NeedVerification int32 `protobuf:"bytes,13,opt,name=needVerification" json:"needVerification,omitempty"`
//}
@@ -156,16 +154,17 @@ type ApplicationGroupResponseReq struct {
HandleResult int32 `json:"handleResult" binding:"required,oneof=-1 1"`
}
type ApplicationGroupResponseResp struct {
CommResp
}
type JoinGroupReq struct {
GroupID string `json:"groupID" binding:"required"`
ReqMessage string `json:"reqMessage"`
OperationID string `json:"operationID" binding:"required"`
GroupID string `json:"groupID" binding:"required"`
ReqMessage string `json:"reqMessage"`
OperationID string `json:"operationID" binding:"required"`
JoinSource int32 `json:"joinSource"`
InviterUserID string `json:"inviterUserID"`
}
type JoinGroupResp struct {
CommResp
}
type QuitGroupReq struct {
@@ -173,20 +172,22 @@ type QuitGroupReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type QuitGroupResp struct {
CommResp
}
type SetGroupInfoReq struct {
GroupID string `json:"groupID" binding:"required"`
GroupName string `json:"groupName"`
Notification string `json:"notification"`
Introduction string `json:"introduction"`
FaceURL string `json:"faceURL"`
Ex string `json:"ex"`
OperationID string `json:"operationID" binding:"required"`
GroupID string `json:"groupID" binding:"required"`
GroupName string `json:"groupName"`
Notification string `json:"notification"`
Introduction string `json:"introduction"`
FaceURL string `json:"faceURL"`
Ex string `json:"ex"`
OperationID string `json:"operationID" binding:"required"`
NeedVerification *int32 `json:"needVerification"`
LookMemberInfo *int32 `json:"lookMemberInfo"`
ApplyMemberFriend *int32 `json:"applyMemberFriend"`
}
type SetGroupInfoResp struct {
CommResp
}
type TransferGroupOwnerReq struct {
@@ -196,7 +197,6 @@ type TransferGroupOwnerReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type TransferGroupOwnerResp struct {
CommResp
}
type DismissGroupReq struct {
@@ -204,7 +204,6 @@ type DismissGroupReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type DismissGroupResp struct {
CommResp
}
type MuteGroupMemberReq struct {
@@ -214,7 +213,6 @@ type MuteGroupMemberReq struct {
MutedSeconds uint32 `json:"mutedSeconds" binding:"required"`
}
type MuteGroupMemberResp struct {
CommResp
}
type CancelMuteGroupMemberReq struct {
@@ -223,7 +221,6 @@ type CancelMuteGroupMemberReq struct {
UserID string `json:"userID" binding:"required"`
}
type CancelMuteGroupMemberResp struct {
CommResp
}
type MuteGroupReq struct {
@@ -231,7 +228,6 @@ type MuteGroupReq struct {
GroupID string `json:"groupID" binding:"required"`
}
type MuteGroupResp struct {
CommResp
}
type CancelMuteGroupReq struct {
@@ -239,7 +235,6 @@ type CancelMuteGroupReq struct {
GroupID string `json:"groupID" binding:"required"`
}
type CancelMuteGroupResp struct {
CommResp
}
type SetGroupMemberNicknameReq struct {
@@ -250,5 +245,27 @@ type SetGroupMemberNicknameReq struct {
}
type SetGroupMemberNicknameResp struct {
CommResp
}
type SetGroupMemberInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
GroupID string `json:"groupID" binding:"required"`
UserID string `json:"userID" binding:"required"`
Nickname *string `json:"nickname"`
FaceURL *string `json:"userGroupFaceUrl"`
RoleLevel *int32 `json:"roleLevel" validate:"gte=1,lte=3"`
Ex *string `json:"ex"`
}
type SetGroupMemberInfoResp struct {
}
type GetGroupAbstractInfoReq struct {
OperationID string `json:"operationID"`
GroupID string `json:"groupID"`
}
type GetGroupAbstractInfoResp struct {
GroupMemberNumber int32 `json:"groupMemberNumber"`
GroupMemberListHash uint64 `json:"groupMemberListHash"`
}
+93
View File
@@ -0,0 +1,93 @@
package apistruct
import (
sdkws "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
type DeleteUsersReq struct {
OperationID string `json:"operationID" binding:"required"`
DeleteUserIDList []string `json:"deleteUserIDList" binding:"required"`
}
type DeleteUsersResp struct {
FailedUserIDList []string `json:"data"`
}
type GetAllUsersUidReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetAllUsersUidResp struct {
UserIDList []string `json:"data"`
}
type GetUsersOnlineStatusReq struct {
OperationID string `json:"operationID" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required,lte=200"`
}
type GetUsersOnlineStatusResp struct {
//SuccessResult []*msggateway.GetUsersOnlineStatusResp_SuccessResult `json:"data"`
}
type AccountCheckReq struct {
OperationID string `json:"operationID" binding:"required"`
CheckUserIDList []string `json:"checkUserIDList" binding:"required,lte=100"`
}
type AccountCheckResp struct {
}
type ManagementSendMsg struct {
SendID string `json:"sendID" binding:"required"`
GroupID string `json:"groupID" binding:"required_if=SessionType 2|required_if=SessionType 3"`
SenderNickname string `json:"senderNickname" `
SenderFaceURL string `json:"senderFaceURL" `
SenderPlatformID int32 `json:"senderPlatformID"`
Content map[string]interface{} `json:"content" binding:"required" swaggerignore:"true"`
ContentType int32 `json:"contentType" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
IsOnlineOnly bool `json:"isOnlineOnly"`
NotOfflinePush bool `json:"notOfflinePush"`
OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"`
}
type ManagementSendMsgReq struct {
SendID string `json:"sendID" binding:"required"`
RecvID string `json:"recvID" binding:"required_if" message:"recvID is required if sessionType is SingleChatType or NotificationChatType"`
GroupID string `json:"groupID" binding:"required_if" message:"groupID is required if sessionType is GroupChatType or SuperGroupChatType"`
SenderNickname string `json:"senderNickname" `
SenderFaceURL string `json:"senderFaceURL" `
SenderPlatformID int32 `json:"senderPlatformID"`
Content map[string]interface{} `json:"content" binding:"required" swaggerignore:"true"`
ContentType int32 `json:"contentType" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
IsOnlineOnly bool `json:"isOnlineOnly"`
NotOfflinePush bool `json:"notOfflinePush"`
OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"`
}
type ManagementSendMsgResp struct {
ResultList sdkws.UserSendMsgResp `json:"data"`
}
type ManagementBatchSendMsgReq struct {
ManagementSendMsg
IsSendAll bool `json:"isSendAll"`
RecvIDList []string `json:"recvIDList"`
}
type ManagementBatchSendMsgResp struct {
Data struct {
ResultList []*SingleReturnResult `json:"resultList"`
FailedIDList []string
} `json:"data"`
}
type SingleReturnResult struct {
ServerMsgID string `json:"serverMsgID"`
ClientMsgID string `json:"clientMsgID"`
SendTime int64 `json:"sendTime"`
RecvID string `json:"recvID" `
}
type CheckMsgIsSendSuccessReq struct {
OperationID string `json:"operationID"`
}
type CheckMsgIsSendSuccessResp struct {
Status int32 `json:"status"`
}
+200
View File
@@ -0,0 +1,200 @@
package apistruct
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/msg"
sdkws "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
type DelMsgReq struct {
UserID string `json:"userID,omitempty" binding:"required"`
SeqList []uint32 `json:"seqList,omitempty" binding:"required"`
OperationID string `json:"operationID,omitempty" binding:"required"`
}
type DelMsgResp struct {
}
type CleanUpMsgReq struct {
UserID string `json:"userID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type CleanUpMsgResp struct {
}
type DelSuperGroupMsgReq struct {
UserID string `json:"userID" binding:"required"`
GroupID string `json:"groupID" binding:"required"`
SeqList []uint32 `json:"seqList,omitempty"`
IsAllDelete bool `json:"isAllDelete"`
OperationID string `json:"operationID" binding:"required"`
}
type DelSuperGroupMsgResp struct {
}
type MsgDeleteNotificationElem struct {
GroupID string `json:"groupID"`
IsAllDelete bool `json:"isAllDelete"`
SeqList []uint32 `json:"seqList"`
}
type SetMsgMinSeqReq struct {
UserID string `json:"userID" binding:"required"`
GroupID string `json:"groupID"`
MinSeq uint32 `json:"minSeq" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type SetMsgMinSeqResp struct {
}
type ModifyMessageReactionExtensionsReq struct {
OperationID string `json:"operationID" binding:"required"`
conversationID string `json:"conversationID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
ReactionExtensionList map[string]*sdkws.KeyValue `json:"reactionExtensionList,omitempty" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
Ex *string `json:"ex"`
AttachedInfo *string `json:"attachedInfo"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type ModifyMessageReactionExtensionsResp struct {
Data struct {
ResultKeyValue []*msg.KeyValueResp `json:"result"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
IsReact bool `json:"isReact"`
} `json:"data"`
}
//type OperateMessageListReactionExtensionsReq struct {
// OperationID string `json:"operationID" binding:"required"`
// conversationID string `json:"conversationID" binding:"required"`
// SessionType string `json:"sessionType" binding:"required"`
// MessageReactionKeyList []*msg.GetMessageListReactionExtensionsReq_MessageReactionKey `json:"messageReactionKeyList" binding:"required"`
//}
type OperateMessageListReactionExtensionsResp struct {
Data struct {
SuccessList []*msg.ExtendMsgResp `json:"successList"`
FailedList []*msg.ExtendMsgResp `json:"failedList"`
} `json:"data"`
}
type SetMessageReactionExtensionsCallbackReq ModifyMessageReactionExtensionsReq
type SetMessageReactionExtensionsCallbackResp ModifyMessageReactionExtensionsResp
//type GetMessageListReactionExtensionsReq OperateMessageListReactionExtensionsReq
type GetMessageListReactionExtensionsResp struct {
Data []*msg.SingleMessageExtensionResult `json:"data"`
}
type AddMessageReactionExtensionsReq ModifyMessageReactionExtensionsReq
type AddMessageReactionExtensionsResp ModifyMessageReactionExtensionsResp
type DeleteMessageReactionExtensionsReq struct {
OperationID string `json:"operationID" binding:"required"`
conversationID string `json:"conversationID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime" binding:"required"`
ReactionExtensionList []*sdkws.KeyValue `json:"reactionExtensionList" binding:"required"`
}
type DeleteMessageReactionExtensionsResp struct {
Data []*msg.KeyValueResp
}
type PictureBaseInfo struct {
UUID string `mapstructure:"uuid"`
Type string `mapstructure:"type" `
Size int64 `mapstructure:"size" `
Width int32 `mapstructure:"width" `
Height int32 `mapstructure:"height"`
Url string `mapstructure:"url" `
}
type PictureElem struct {
SourcePath string `mapstructure:"sourcePath"`
SourcePicture PictureBaseInfo `mapstructure:"sourcePicture"`
BigPicture PictureBaseInfo `mapstructure:"bigPicture" `
SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture"`
}
type SoundElem struct {
UUID string `mapstructure:"uuid"`
SoundPath string `mapstructure:"soundPath"`
SourceURL string `mapstructure:"sourceUrl"`
DataSize int64 `mapstructure:"dataSize"`
Duration int64 `mapstructure:"duration"`
}
type VideoElem struct {
VideoPath string `mapstructure:"videoPath"`
VideoUUID string `mapstructure:"videoUUID"`
VideoURL string `mapstructure:"videoUrl"`
VideoType string `mapstructure:"videoType"`
VideoSize int64 `mapstructure:"videoSize"`
Duration int64 `mapstructure:"duration"`
SnapshotPath string `mapstructure:"snapshotPath"`
SnapshotUUID string `mapstructure:"snapshotUUID"`
SnapshotSize int64 `mapstructure:"snapshotSize"`
SnapshotURL string `mapstructure:"snapshotUrl"`
SnapshotWidth int32 `mapstructure:"snapshotWidth"`
SnapshotHeight int32 `mapstructure:"snapshotHeight"`
}
type FileElem struct {
FilePath string `mapstructure:"filePath"`
UUID string `mapstructure:"uuid"`
SourceURL string `mapstructure:"sourceUrl"`
FileName string `mapstructure:"fileName"`
FileSize int64 `mapstructure:"fileSize"`
}
type AtElem struct {
Text string `mapstructure:"text"`
AtUserList []string `mapstructure:"atUserList"`
IsAtSelf bool `mapstructure:"isAtSelf"`
}
type LocationElem struct {
Description string `mapstructure:"description"`
Longitude float64 `mapstructure:"longitude"`
Latitude float64 `mapstructure:"latitude"`
}
type CustomElem struct {
Data string `mapstructure:"data" validate:"required"`
Description string `mapstructure:"description"`
Extension string `mapstructure:"extension"`
}
type TextElem struct {
Text string `mapstructure:"text" validate:"required"`
}
type RevokeElem struct {
RevokeMsgClientID string `mapstructure:"revokeMsgClientID" validate:"required"`
}
type OANotificationElem struct {
NotificationName string `mapstructure:"notificationName" json:"notificationName" validate:"required"`
NotificationFaceURL string `mapstructure:"notificationFaceURL" json:"notificationFaceURL"`
NotificationType int32 `mapstructure:"notificationType" json:"notificationType" validate:"required"`
Text string `mapstructure:"text" json:"text" validate:"required"`
Url string `mapstructure:"url" json:"url"`
MixType int32 `mapstructure:"mixType" json:"mixType"`
PictureElem PictureElem `mapstructure:"pictureElem" json:"pictureElem"`
SoundElem SoundElem `mapstructure:"soundElem" json:"soundElem"`
VideoElem VideoElem `mapstructure:"videoElem" json:"videoElem"`
FileElem FileElem `mapstructure:"fileElem" json:"fileElem"`
Ex string `mapstructure:"ex" json:"ex"`
}
type MessageRevoked struct {
RevokerID string `mapstructure:"revokerID" json:"revokerID" validate:"required"`
RevokerRole int32 `mapstructure:"revokerRole" json:"revokerRole" validate:"required"`
ClientMsgID string `mapstructure:"clientMsgID" json:"clientMsgID" validate:"required"`
RevokerNickname string `mapstructure:"revokerNickname" json:"revokerNickname"`
SessionType int32 `mapstructure:"sessionType" json:"sessionType" validate:"required"`
Seq uint32 `mapstructure:"seq" json:"seq" validate:"required"`
}
@@ -1,4 +1,4 @@
package base_info
package apistruct
type OSSCredentialReq struct {
OperationID string `json:"operationID"`
@@ -16,7 +16,6 @@ type OSSCredentialRespData struct {
}
type OSSCredentialResp struct {
CommResp
OssData OSSCredentialRespData `json:"-"`
Data map[string]interface{} `json:"data"`
}
+6
View File
@@ -0,0 +1,6 @@
package apistruct
type Pagination struct {
PageNumber int32 `json:"pageNumber" binding:"required"`
ShowNumber int32 `json:"showNumber" binding:"required"`
}
+18
View File
@@ -0,0 +1,18 @@
package apistruct
type ApiUserInfo struct {
UserID string `json:"userID" binding:"required,min=1,max=64" swaggo:"true,用户ID,"`
Nickname string `json:"nickname" binding:"omitempty,min=1,max=64" swaggo:"true,my id,19"`
FaceURL string `json:"faceURL" binding:"omitempty,max=1024"`
Gender int32 `json:"gender" binding:"omitempty,oneof=0 1 2"`
PhoneNumber string `json:"phoneNumber" binding:"omitempty,max=32"`
Birth int64 `json:"birth" binding:"omitempty"`
Email string `json:"email" binding:"omitempty,max=64"`
CreateTime int64 `json:"createTime"`
Ex string `json:"ex" binding:"omitempty,max=1024"`
}
type GroupAddMemberInfo struct {
UserID string `json:"userID" binding:"required"`
RoleLevel int32 `json:"roleLevel" binding:"required,oneof= 1 3"`
}
+17
View File
@@ -0,0 +1,17 @@
package apistruct
type GetJoinedSuperGroupListReq struct {
GetJoinedGroupListReq
}
type GetJoinedSuperGroupListResp struct {
GetJoinedGroupListResp
}
type GetSuperGroupsInfoReq struct {
GetGroupInfoReq
}
type GetSuperGroupsInfoResp struct {
GetGroupInfoResp
}
+117
View File
@@ -0,0 +1,117 @@
package apistruct
import "mime/multipart"
type MinioStorageCredentialReq struct {
OperationID string `json:"operationID"`
}
type MiniostorageCredentialResp struct {
SecretAccessKey string `json:"secretAccessKey"`
AccessKeyID string `json:"accessKeyID"`
SessionToken string `json:"sessionToken"`
BucketName string `json:"bucketName"`
StsEndpointURL string `json:"stsEndpointURL"`
StorageTime int `json:"storageTime"`
IsDistributedMod bool `json:"isDistributedMod"`
}
type MinioUploadFileReq struct {
OperationID string `form:"operationID" binding:"required"`
FileType int `form:"fileType" binding:"required"`
}
type MinioUploadFile struct {
URL string `json:"URL"`
NewName string `json:"newName"`
SnapshotURL string `json:"snapshotURL,omitempty"`
SnapshotNewName string `json:"snapshotName,omitempty"`
}
type MinioUploadFileResp struct {
Data struct {
MinioUploadFile
} `json:"data"`
}
type UploadUpdateAppReq struct {
OperationID string `form:"operationID" binding:"required"`
Type int `form:"type" binding:"required"`
Version string `form:"version" binding:"required"`
File *multipart.FileHeader `form:"file" binding:"required"`
Yaml *multipart.FileHeader `form:"yaml"`
ForceUpdate bool `form:"forceUpdate"`
UpdateLog string `form:"updateLog" binding:"required"`
}
type UploadUpdateAppResp struct {
}
type GetDownloadURLReq struct {
OperationID string `json:"operationID" binding:"required"`
Type int `json:"type" binding:"required"`
Version string `json:"version" binding:"required"`
}
type GetDownloadURLResp struct {
Data struct {
HasNewVersion bool `json:"hasNewVersion"`
ForceUpdate bool `json:"forceUpdate"`
FileURL string `json:"fileURL"`
YamlURL string `json:"yamlURL"`
Version string `json:"version"`
UpdateLog string `json:"update_log"`
} `json:"data"`
}
type GetRTCInvitationInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
}
type GetRTCInvitationInfoResp struct {
Data struct {
OpUserID string `json:"opUserID"`
Invitation struct {
InviterUserID string `json:"inviterUserID"`
InviteeUserIDList []string `json:"inviteeUserIDList"`
GroupID string `json:"groupID"`
RoomID string `json:"roomID"`
Timeout int32 `json:"timeout"`
MediaType string `json:"mediaType"`
SessionType int32 `json:"sessionType"`
InitiateTime int32 `json:"initiateTime"`
PlatformID int32 `json:"platformID"`
CustomData string `json:"customData"`
} `json:"invitation"`
OfflinePushInfo struct{} `json:"offlinePushInfo"`
} `json:"data"`
}
type GetRTCInvitationInfoStartAppReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetRTCInvitationInfoStartAppResp struct {
GetRTCInvitationInfoResp
}
/**
* FCM第三方上报Token
*/
type FcmUpdateTokenReq struct {
OperationID string `json:"operationID" binding:"required"`
Platform int `json:"platform" binding:"required,min=1,max=2"` //only for ios + android
FcmToken string `json:"fcmToken" binding:"required"`
}
type FcmUpdateTokenResp struct {
}
type SetAppBadgeReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
AppUnreadCount int32 `json:"appUnreadCount"`
}
type SetAppBadgeResp struct {
}
-39
View File
@@ -1,39 +0,0 @@
package base_info
//UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"`
// Nickname string `protobuf:"bytes,2,opt,name=Nickname" json:"Nickname,omitempty"`
// FaceUrl string `protobuf:"bytes,3,opt,name=FaceUrl" json:"FaceUrl,omitempty"`
// Gender int32 `protobuf:"varint,4,opt,name=Gender" json:"Gender,omitempty"`
// PhoneNumber string `protobuf:"bytes,5,opt,name=PhoneNumber" json:"PhoneNumber,omitempty"`
// Birth string `protobuf:"bytes,6,opt,name=Birth" json:"Birth,omitempty"`
// Email string `protobuf:"bytes,7,opt,name=Email" json:"Email,omitempty"`
// Ex string `protobuf:"bytes,8,opt,name=Ex" json:"Ex,omitempty"`
type UserRegisterReq struct {
Secret string `json:"secret" binding:"required,max=32"`
Platform int32 `json:"platform" binding:"required,min=1,max=7"`
ApiUserInfo
OperationID string `json:"operationID" binding:"required"`
}
type UserTokenInfo struct {
UserID string `json:"userID"`
Token string `json:"token"`
ExpiredTime int64 `json:"expiredTime"`
}
type UserRegisterResp struct {
CommResp
UserToken UserTokenInfo `json:"data"`
}
type UserTokenReq struct {
Secret string `json:"secret" binding:"required,max=32"`
Platform int32 `json:"platform" binding:"required,min=1,max=8"`
UserID string `json:"userID" binding:"required,min=1,max=64"`
OperationID string `json:"operationID" binding:"required"`
}
type UserTokenResp struct {
CommResp
UserToken UserTokenInfo `json:"data"`
}
-136
View File
@@ -1,136 +0,0 @@
package base_info
import open_im_sdk "Open_IM/pkg/proto/sdk_ws"
type ParamsCommFriend struct {
OperationID string `json:"operationID" binding:"required"`
ToUserID string `json:"toUserID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type AddBlacklistReq struct {
ParamsCommFriend
}
type AddBlacklistResp struct {
CommResp
}
type ImportFriendReq struct {
FriendUserIDList []string `json:"friendUserIDList" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type UserIDResult struct {
UserID string `json:"userID"`
Result int32 `json:"result"`
}
type ImportFriendResp struct {
CommResp
UserIDResultList []UserIDResult `json:"data"`
}
type AddFriendReq struct {
ParamsCommFriend
ReqMsg string `json:"reqMsg"`
}
type AddFriendResp struct {
CommResp
}
type AddFriendResponseReq struct {
ParamsCommFriend
Flag int32 `json:"flag" binding:"required,oneof=-1 0 1"`
HandleMsg string `json:"handleMsg"`
}
type AddFriendResponseResp struct {
CommResp
}
type DeleteFriendReq struct {
ParamsCommFriend
}
type DeleteFriendResp struct {
CommResp
}
type GetBlackListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetBlackListResp struct {
CommResp
BlackUserInfoList []*open_im_sdk.PublicUserInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
}
//type PublicUserInfo struct {
// UserID string `json:"userID"`
// Nickname string `json:"nickname"`
// FaceUrl string `json:"faceUrl"`
// Gender int32 `json:"gender"`
//}
type SetFriendRemarkReq struct {
ParamsCommFriend
Remark string `json:"remark" binding:"required"`
}
type SetFriendRemarkResp struct {
CommResp
}
type RemoveBlackListReq struct {
ParamsCommFriend
}
type RemoveBlackListResp struct {
CommResp
}
type IsFriendReq struct {
ParamsCommFriend
}
type Response struct {
Friend bool `json:"isFriend"`
}
type IsFriendResp struct {
CommResp
Response Response `json:"data"`
}
type GetFriendsInfoReq struct {
ParamsCommFriend
}
type GetFriendsInfoResp struct {
CommResp
FriendInfoList []*open_im_sdk.FriendInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type GetFriendListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetFriendListResp struct {
CommResp
FriendInfoList []*open_im_sdk.FriendInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type GetFriendApplyListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetFriendApplyListResp struct {
CommResp
FriendRequestList []*open_im_sdk.FriendRequest `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type GetSelfApplyListReq struct {
OperationID string `json:"operationID" binding:"required"`
FromUserID string `json:"fromUserID" binding:"required"`
}
type GetSelfApplyListResp struct {
CommResp
FriendRequestList []*open_im_sdk.FriendRequest `json:"-"`
Data []map[string]interface{} `json:"data"`
}
-44
View File
@@ -1,44 +0,0 @@
package base_info
import (
pbRelay "Open_IM/pkg/proto/relay"
"Open_IM/pkg/proto/sdk_ws"
pbUser "Open_IM/pkg/proto/user"
)
type DeleteUsersReq struct {
OperationID string `json:"operationID" binding:"required"`
DeleteUserIDList []string `json:"deleteUserIDList" binding:"required"`
}
type DeleteUsersResp struct {
CommResp
FailedUserIDList []string `json:"data"`
}
type GetAllUsersUidReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetAllUsersUidResp struct {
CommResp
UserIDList []string `json:"data"`
}
type GetUsersOnlineStatusReq struct {
OperationID string `json:"operationID" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required,lte=200"`
}
type GetUsersOnlineStatusResp struct {
CommResp
SuccessResult []*pbRelay.GetUsersOnlineStatusResp_SuccessResult `json:"data"`
}
type AccountCheckReq struct {
OperationID string `json:"operationID" binding:"required"`
CheckUserIDList []string `json:"checkUserIDList" binding:"required,lte=100"`
}
type AccountCheckResp struct {
CommResp
ResultList []*pbUser.AccountCheckResp_SingleUserStatus `json:"data"`
}
type ManagementSendMsgResp struct {
CommResp
ResultList server_api_params.UserSendMsgResp `json:"data"`
}
-56
View File
@@ -1,56 +0,0 @@
package base_info
import "mime/multipart"
type MinioStorageCredentialReq struct {
OperationID string `json:"operationID"`
}
type MiniostorageCredentialResp struct {
SecretAccessKey string `json:"secretAccessKey"`
AccessKeyID string `json:"accessKeyID"`
SessionToken string `json:"sessionToken"`
BucketName string `json:"bucketName"`
StsEndpointURL string `json:"stsEndpointURL"`
}
type MinioUploadFileReq struct {
OperationID string `form:"operationID" binding:"required"`
FileType int `form:"fileType" binding:"required"`
}
type MinioUploadFileResp struct {
URL string `json:"URL"`
NewName string `json:"newName"`
SnapshotURL string `json:"snapshotURL,omitempty"`
SnapshotNewName string `json:"snapshotName,omitempty"`
}
type UploadUpdateAppReq struct {
OperationID string `form:"operationID" binding:"required"`
Type int `form:"type" binding:"required"`
Version string `form:"version" binding:"required"`
File *multipart.FileHeader `form:"file" binding:"required"`
Yaml *multipart.FileHeader `form:"yaml" binding:"required"`
ForceUpdate bool `form:"forceUpdate" binding:"required"`
}
type UploadUpdateAppResp struct {
CommResp
}
type GetDownloadURLReq struct {
OperationID string `json:"operationID" binding:"required"`
Type int `json:"type" binding:"required"`
Version string `json:"version" binding:"required"`
}
type GetDownloadURLResp struct {
CommResp
Data struct {
HasNewVersion bool `json:"hasNewVersion"`
ForceUpdate bool `json:"forceUpdate"`
FileURL string `json:"fileURL"`
YamlURL string `json:"yamlURL"`
} `json:"data"`
}
-12
View File
@@ -1,12 +0,0 @@
package base_info
type DelMsgReq struct {
OpUserID string `json:"opUserID,omitempty"`
UserID string `json:"userID,omitempty"`
SeqList []uint32 `json:"seqList,omitempty"`
OperationID string `json:"operationID,omitempty"`
}
type DelMsgResp struct {
CommResp
}
-88
View File
@@ -1,88 +0,0 @@
package base_info
import (
pbOffice "Open_IM/pkg/proto/office"
)
type GetUserTagsReq struct {
OperationID string `json:"operationID" binding:"required"`
}
type GetUserTagsResp struct {
CommResp
Data struct {
Tags []*pbOffice.Tag `json:"tags"`
} `json:"data"`
}
type CreateTagReq struct {
TagName string `json:"tagName" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type CreateTagResp struct {
CommResp
}
type DeleteTagReq struct {
TagID string `json:"tagID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type DeleteTagResp struct {
CommResp
}
type SetTagReq struct {
TagID string `json:"tagID" binding:"required"`
NewName string `json:"newName"`
IncreaseUserIDList []string `json:"increaseUserIDList"`
ReduceUserIDList []string `json:"reduceUserIDList"`
OperationID string `json:"operationID" binding:"required"`
}
type SetTagResp struct {
CommResp
}
type SendMsg2TagReq struct {
TagList []string `json:"tagList"`
UserList []string `json:"userList"`
GroupList []string `json:"groupList"`
SenderPlatformID int32 `json:"senderPlatformID" binding:"required"`
Content string `json:"content" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type SendMsg2TagResp struct {
CommResp
}
type GetTagSendLogsReq struct {
PageNumber int32 `json:"pageNumber" binding:"required"`
ShowNumber int32 `json:"showNumber" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type GetTagSendLogsResp struct {
CommResp
Data struct {
Logs []*pbOffice.TagSendLog `json:"logs"`
CurrentPage int32 `json:"currentPage"`
ShowNumber int32 `json:"showNumber"`
} `json:"data"`
}
type GetUserTagByIDReq struct {
TagID string `json:"tagID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type GetUserTagByIDResp struct {
CommResp
Data struct {
Tag *pbOffice.Tag `json:"tag"`
} `json:"data"`
}
-121
View File
@@ -1,121 +0,0 @@
package base_info
import open_im_sdk "Open_IM/pkg/proto/sdk_ws"
type CreateDepartmentReq struct {
*open_im_sdk.Department
OperationID string `json:"operationID" binding:"required"`
}
type CreateDepartmentResp struct {
CommResp
Department *open_im_sdk.Department `json:"-"`
Data map[string]interface{} `json:"data"`
}
type UpdateDepartmentReq struct {
*open_im_sdk.Department
DepartmentID string `json:"departmentID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type UpdateDepartmentResp struct {
CommResp
}
type GetSubDepartmentReq struct {
OperationID string `json:"operationID" binding:"required"`
DepartmentID string `json:"departmentID" binding:"required"`
}
type GetSubDepartmentResp struct {
CommResp
DepartmentList []*open_im_sdk.Department `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type DeleteDepartmentReq struct {
OperationID string `json:"operationID" binding:"required"`
DepartmentID string `json:"departmentID" binding:"required"`
}
type DeleteDepartmentResp struct {
CommResp
}
type CreateOrganizationUserReq struct {
OperationID string `json:"operationID" binding:"required"`
*open_im_sdk.OrganizationUser
}
type CreateOrganizationUserResp struct {
CommResp
}
type UpdateOrganizationUserReq struct {
OperationID string `json:"operationID" binding:"required"`
*open_im_sdk.OrganizationUser
}
type UpdateOrganizationUserResp struct {
CommResp
}
type CreateDepartmentMemberReq struct {
OperationID string `json:"operationID" binding:"required"`
*open_im_sdk.DepartmentMember
}
type CreateDepartmentMemberResp struct {
CommResp
}
type GetUserInDepartmentReq struct {
UserID string `json:"userID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type GetUserInDepartmentResp struct {
CommResp
UserInDepartment *open_im_sdk.UserInDepartment `json:"-"`
Data map[string]interface{} `json:"data"`
}
type UpdateUserInDepartmentReq struct {
OperationID string `json:"operationID" binding:"required"`
*open_im_sdk.DepartmentMember
}
type UpdateUserInDepartmentResp struct {
CommResp
}
type DeleteOrganizationUserReq struct {
UserID string `json:"userID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type DeleteOrganizationUserResp struct {
CommResp
}
type GetDepartmentMemberReq struct {
DepartmentID string `json:"departmentID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type GetDepartmentMemberResp struct {
CommResp
UserInDepartmentList []*open_im_sdk.UserDepartmentMember `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type DeleteUserInDepartmentReq struct {
DepartmentID string `json:"departmentID" binding:"required"`
UserID string `json:"userID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type DeleteUserInDepartmentResp struct {
CommResp
}
type GetUserInOrganizationReq struct {
OperationID string `json:"operationID" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required"`
}
type GetUserInOrganizationResp struct {
CommResp
OrganizationUserList []*open_im_sdk.OrganizationUser `json:"-"`
Data []map[string]interface{} `json:"data" swaggerignore:"true"`
}
-140
View File
@@ -1,140 +0,0 @@
package base_info
import (
"github.com/gin-gonic/gin"
"net/http"
)
type ApiUserInfo struct {
UserID string `json:"userID" binding:"required,min=1,max=64"`
Nickname string `json:"nickname" binding:"omitempty,min=1,max=64"`
FaceURL string `json:"faceURL" binding:"omitempty,max=1024"`
Gender int32 `json:"gender" binding:"omitempty,oneof=0 1 2"`
PhoneNumber string `json:"phoneNumber" binding:"omitempty,max=32"`
Birth uint32 `json:"birth" binding:"omitempty"`
Email string `json:"email" binding:"omitempty,max=64"`
GlobalRecvMsgOpt *int32 `json:"globalRecvMsgOpt" binding:"omitempty,oneof=0 1 2"`
Ex string `json:"ex" binding:"omitempty,max=1024"`
}
//type Conversation struct {
// OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"`
// ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"`
// ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"`
// UserID string `gorm:"column:user_id;type:char(64)" json:"userID"`
// GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"`
// RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"`
// UnreadCount int32 `gorm:"column:unread_count" json:"unreadCount"`
// DraftTextTime int64 `gorm:"column:draft_text_time" json:"draftTextTime"`
// IsPinned bool `gorm:"column:is_pinned" json:"isPinned"`
// AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"`
// Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
//}
type GroupAddMemberInfo struct {
UserID string `json:"userID" binding:"required"`
RoleLevel int32 `json:"roleLevel" binding:"required"`
}
func SetErrCodeMsg(c *gin.Context, status int) *CommResp {
resp := CommResp{ErrCode: int32(status), ErrMsg: http.StatusText(status)}
c.JSON(status, resp)
return &resp
}
//GroupName string `json:"groupName"`
// Introduction string `json:"introduction"`
// Notification string `json:"notification"`
// FaceUrl string `json:"faceUrl"`
// OperationID string `json:"operationID" binding:"required"`
// GroupType int32 `json:"groupType"`
// Ex string `json:"ex"`
//type GroupInfo struct {
// GroupID string `json:"groupID"`
// GroupName string `json:"groupName"`
// Notification string `json:"notification"`
// Introduction string `json:"introduction"`
// FaceUrl string `json:"faceUrl"`
// OwnerUserID string `json:"ownerUserID"`
// Ex string `json:"ex"`
// GroupType int32 `json:"groupType"`
//}
//type GroupMemberFullInfo struct {
// GroupID string `json:"groupID"`
// UserID string `json:"userID"`
// RoleLevel int32 `json:"roleLevel"`
// JoinTime uint64 `json:"joinTime"`
// Nickname string `json:"nickname"`
// FaceUrl string `json:"faceUrl"`
// FriendRemark string `json:"friendRemark"`
// AppMangerLevel int32 `json:"appMangerLevel"`
// JoinSource int32 `json:"joinSource"`
// OperatorUserID string `json:"operatorUserID"`
// Ex string `json:"ex"`
//}
//
//type PublicUserInfo struct {
// UserID string `json:"userID"`
// Nickname string `json:"nickname"`
// FaceUrl string `json:"faceUrl"`
// Gender int32 `json:"gender"`
//}
//
//type UserInfo struct {
// UserID string `json:"userID"`
// Nickname string `json:"nickname"`
// FaceUrl string `json:"faceUrl"`
// Gender int32 `json:"gender"`
// Mobile string `json:"mobile"`
// Birth string `json:"birth"`
// Email string `json:"email"`
// Ex string `json:"ex"`
//}
//
//type FriendInfo struct {
// OwnerUserID string `json:"ownerUserID"`
// Remark string `json:"remark"`
// CreateTime int64 `json:"createTime"`
// FriendUser UserInfo `json:"friendUser"`
// AddSource int32 `json:"addSource"`
// OperatorUserID string `json:"operatorUserID"`
// Ex string `json:"ex"`
//}
//
//type BlackInfo struct {
// OwnerUserID string `json:"ownerUserID"`
// CreateTime int64 `json:"createTime"`
// BlackUser PublicUserInfo `json:"friendUser"`
// AddSource int32 `json:"addSource"`
// OperatorUserID string `json:"operatorUserID"`
// Ex string `json:"ex"`
//}
//
//type GroupRequest struct {
// UserID string `json:"userID"`
// GroupID string `json:"groupID"`
// HandleResult string `json:"handleResult"`
// ReqMsg string `json:"reqMsg"`
// HandleMsg string `json:"handleMsg"`
// ReqTime int64 `json:"reqTime"`
// HandleUserID string `json:"handleUserID"`
// HandleTime int64 `json:"handleTime"`
// Ex string `json:"ex"`
//}
//
//type FriendRequest struct {
// FromUserID string `json:"fromUserID"`
// ToUserID string `json:"toUserID"`
// HandleResult int32 `json:"handleResult"`
// ReqMessage string `json:"reqMessage"`
// CreateTime int64 `json:"createTime"`
// HandlerUserID string `json:"handlerUserID"`
// HandleMsg string `json:"handleMsg"`
// HandleTime int64 `json:"handleTime"`
// Ex string `json:"ex"`
//}
//
//
//
-34
View File
@@ -1,34 +0,0 @@
package base_info
import (
open_im_sdk "Open_IM/pkg/proto/sdk_ws"
)
type GetUsersInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required"`
}
type GetUsersInfoResp struct {
CommResp
UserInfoList []*open_im_sdk.PublicUserInfo `json:"-"`
Data []map[string]interface{} `json:"data"`
}
type UpdateSelfUserInfoReq struct {
ApiUserInfo
OperationID string `json:"operationID" binding:"required"`
}
type UpdateUserInfoResp struct {
CommResp
}
type GetSelfUserInfoReq struct {
OperationID string `json:"operationID" binding:"required"`
UserID string `json:"userID" binding:"required"`
}
type GetSelfUserInfoResp struct {
CommResp
UserInfo *open_im_sdk.UserInfo `json:"-"`
Data map[string]interface{} `json:"data"`
}
-98
View File
@@ -1,98 +0,0 @@
package base_info
import "Open_IM/pkg/proto/office"
type CreateOneWorkMomentReq struct {
office.CreateOneWorkMomentReq
}
type CreateOneWorkMomentResp struct {
CommResp
}
type DeleteOneWorkMomentReq struct {
office.DeleteOneWorkMomentReq
}
type DeleteOneWorkMomentResp struct {
CommResp
}
type LikeOneWorkMomentReq struct {
office.LikeOneWorkMomentReq
}
type LikeOneWorkMomentResp struct {
CommResp
}
type CommentOneWorkMomentReq struct {
office.CommentOneWorkMomentReq
}
type CommentOneWorkMomentResp struct {
CommResp
}
type WorkMomentsUserCommonReq struct {
PageNumber int32 `json:"pageNumber" binding:"required"`
ShowNumber int32 `json:"showNumber" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
UserID string `json:"UserID" binding:"required"`
}
type GetUserWorkMomentsReq struct {
WorkMomentsUserCommonReq
UserID string `json:"userID"`
}
type GetUserWorkMomentsResp struct {
CommResp
Data struct {
WorkMoments []*office.WorkMoment `json:"workMoments"`
CurrentPage int32 `json:"currentPage"`
ShowNumber int32 `json:"showNumber"`
} `json:"data"`
}
type GetUserFriendWorkMomentsReq struct {
WorkMomentsUserCommonReq
}
type GetUserFriendWorkMomentsResp struct {
CommResp
Data struct {
WorkMoments []*office.WorkMoment `json:"workMoments"`
CurrentPage int32 `json:"currentPage"`
ShowNumber int32 `json:"showNumber"`
} `json:"data"`
}
type GetUserWorkMomentsCommentsMsgReq struct {
WorkMomentsUserCommonReq
}
type GetUserWorkMomentsCommentsMsgResp struct {
CommResp
Data struct {
CommentMsgs []*office.CommentsMsg `json:"comments"`
CurrentPage int32 `json:"currentPage"`
ShowNumber int32 `json:"showNumber"`
} `json:"data"`
}
type SetUserWorkMomentsLevelReq struct {
office.SetUserWorkMomentsLevelReq
}
type SetUserWorkMomentsLevelResp struct {
CommResp
}
type ClearUserWorkMomentsCommentsMsgReq struct {
office.ClearUserWorkMomentsCommentsMsgReq
}
type ClearUserWorkMomentsCommentsMsgResp struct {
CommResp
}
-24
View File
@@ -1,24 +0,0 @@
package call_back_struct
type CommonCallbackReq struct {
SendID string `json:"sendID"`
CallbackCommand string `json:"callbackCommand"`
ServerMsgID string `json:"serverMsgID"`
ClientMsgID string `json:"clientMsgID"`
OperationID string `json:"operationID"`
SenderPlatformID int32 `json:"senderPlatformID"`
SenderNickname string `json:"senderNickname"`
SessionType int32 `json:"sessionType"`
MsgFrom int32 `json:"msgFrom"`
ContentType int32 `json:"contentType"`
Status int32 `json:"status"`
CreateTime int64 `json:"createTime"`
Content string `json:"content"`
}
type CommonCallbackResp struct {
ActionCode int `json:"actionCode"`
ErrCode int `json:"errCode"`
ErrMsg string `json:"errMsg"`
OperationID string `json:"operationID"`
}
-9
View File
@@ -1,9 +0,0 @@
package call_back_struct
type CallbackBeforeCreateGroupReq struct {
CommonCallbackReq
}
type CallbackAfterCreateGroupResp struct {
CommonCallbackResp
}
-49
View File
@@ -1,49 +0,0 @@
package call_back_struct
type CallbackBeforeSendSingleMsgReq struct {
CommonCallbackReq
RecvID string `json:"recvID"`
}
type CallbackBeforeSendSingleMsgResp struct {
CommonCallbackResp
}
type CallbackAfterSendSingleMsgReq struct {
CommonCallbackReq
RecvID string `json:"recvID"`
}
type CallbackAfterSendSingleMsgResp struct {
CommonCallbackResp
}
type CallbackBeforeSendGroupMsgReq struct {
CommonCallbackReq
GroupID string `json:"groupID"`
}
type CallbackBeforeSendGroupMsgResp struct {
CommonCallbackResp
}
type CallbackAfterSendGroupMsgReq struct {
CommonCallbackReq
GroupID string `json:"groupID"`
}
type CallbackAfterSendGroupMsgResp struct {
CommonCallbackResp
}
type CallbackWordFilterReq struct {
CommonCallbackReq
RecvID string `json:"recvID,omitempty"`
GroupID string `json:"groupID,omitempty"`
}
type CallbackWordFilterResp struct {
CommonCallbackResp
Content string `json:"content"`
}
+72
View File
@@ -0,0 +1,72 @@
package callbackstruct
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
)
type CommonCallbackReq struct {
SendID string `json:"sendID"`
CallbackCommand string `json:"callbackCommand"`
ServerMsgID string `json:"serverMsgID"`
ClientMsgID string `json:"clientMsgID"`
OperationID string `json:"operationID"`
SenderPlatformID int32 `json:"senderPlatformID"`
SenderNickname string `json:"senderNickname"`
SessionType int32 `json:"sessionType"`
MsgFrom int32 `json:"msgFrom"`
ContentType int32 `json:"contentType"`
Status int32 `json:"status"`
CreateTime int64 `json:"createTime"`
Content string `json:"content"`
Seq uint32 `json:"seq"`
AtUserIDList []string `json:"atUserList"`
SenderFaceURL string `json:"faceURL"`
Ex string `json:"ex"`
}
func (c *CommonCallbackReq) GetCallbackCommand() string {
return c.CallbackCommand
}
type CallbackReq interface {
GetCallbackCommand() string
}
type CallbackResp interface {
Parse() (err error)
}
type CommonCallbackResp struct {
ActionCode int `json:"actionCode"`
ErrCode int32 `json:"errCode"`
ErrMsg string `json:"errMsg"`
ErrDlt string `json:"errDlt"`
}
func (c CommonCallbackResp) Parse() error {
if c.ActionCode != errs.NoError || c.ErrCode != errs.NoError {
return errs.NewCodeError(int(c.ErrCode), c.ErrMsg).WithDetail(c.ErrDlt)
}
return nil
}
type UserStatusBaseCallback struct {
CallbackCommand string `json:"callbackCommand"`
OperationID string `json:"operationID"`
PlatformID int `json:"platformID"`
Platform string `json:"platform"`
}
func (c UserStatusBaseCallback) GetCallbackCommand() string {
return c.CallbackCommand
}
type UserStatusCallbackReq struct {
UserStatusBaseCallback
UserID string `json:"userID"`
}
type UserStatusBatchCallbackReq struct {
UserStatusBaseCallback
UserIDList []string `json:"userIDList"`
}
+13
View File
@@ -0,0 +1,13 @@
package callbackstruct
type CallbackBeforeAddFriendReq struct {
CallbackCommand `json:"callbackCommand"`
FromUserID string `json:"fromUserID" `
ToUserID string `json:"toUserID"`
ReqMsg string `json:"reqMsg"`
OperationID string `json:"operationID"`
}
type CallbackBeforeAddFriendResp struct {
CommonCallbackResp
}
+73
View File
@@ -0,0 +1,73 @@
package callbackstruct
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/apistruct"
common "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
type CallbackCommand string
func (c CallbackCommand) GetCallbackCommand() string {
return string(c)
}
type CallbackBeforeCreateGroupReq struct {
OperationID string `json:"operationID"`
CallbackCommand `json:"callbackCommand"`
*common.GroupInfo
InitMemberList []*apistruct.GroupAddMemberInfo `json:"initMemberList"`
}
type CallbackBeforeCreateGroupResp struct {
CommonCallbackResp
GroupID *string `json:"groupID"`
GroupName *string `json:"groupName"`
Notification *string `json:"notification"`
Introduction *string `json:"introduction"`
FaceURL *string `json:"faceURL"`
OwnerUserID *string `json:"ownerUserID"`
Ex *string `json:"ex"`
Status *int32 `json:"status"`
CreatorUserID *string `json:"creatorUserID"`
GroupType *int32 `json:"groupType"`
NeedVerification *int32 `json:"needVerification"`
LookMemberInfo *int32 `json:"lookMemberInfo"`
ApplyMemberFriend *int32 `json:"applyMemberFriend"`
}
type CallbackBeforeMemberJoinGroupReq struct {
CallbackCommand `json:"callbackCommand"`
OperationID string `json:"operationID"`
GroupID string `json:"groupID"`
UserID string `json:"userID"`
Ex string `json:"ex"`
GroupEx string `json:"groupEx"`
}
type CallbackBeforeMemberJoinGroupResp struct {
CommonCallbackResp
Nickname *string `json:"nickname"`
FaceURL *string `json:"faceURL"`
RoleLevel *int32 `json:"roleLevel"`
MuteEndTime *int64 `json:"muteEndTime"`
Ex *string `json:"ex"`
}
type CallbackBeforeSetGroupMemberInfoReq struct {
CallbackCommand `json:"callbackCommand"`
OperationID string `json:"operationID"`
GroupID string `json:"groupID"`
UserID string `json:"userID"`
Nickname *string `json:"nickName"`
FaceURL *string `json:"faceURL"`
RoleLevel *int32 `json:"roleLevel"`
Ex *string `json:"ex"`
}
type CallbackBeforeSetGroupMemberInfoResp struct {
CommonCallbackResp
Ex *string `json:"ex"`
Nickname *string `json:"nickName"`
FaceURL *string `json:"faceURL"`
RoleLevel *int32 `json:"roleLevel"`
}
+136
View File
@@ -0,0 +1,136 @@
package callbackstruct
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/msg"
sdkws "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
type CallbackBeforeSendSingleMsgReq struct {
CommonCallbackReq
RecvID string `json:"recvID"`
}
type CallbackBeforeSendSingleMsgResp struct {
CommonCallbackResp
}
type CallbackAfterSendSingleMsgReq struct {
CommonCallbackReq
RecvID string `json:"recvID"`
}
type CallbackAfterSendSingleMsgResp struct {
CommonCallbackResp
}
type CallbackBeforeSendGroupMsgReq struct {
CommonCallbackReq
GroupID string `json:"groupID"`
}
type CallbackBeforeSendGroupMsgResp struct {
CommonCallbackResp
}
type CallbackAfterSendGroupMsgReq struct {
CommonCallbackReq
GroupID string `json:"groupID"`
}
type CallbackAfterSendGroupMsgResp struct {
CommonCallbackResp
}
type CallbackMsgModifyCommandReq struct {
CommonCallbackReq
}
type CallbackMsgModifyCommandResp struct {
CommonCallbackResp
Content *string `json:"content"`
RecvID *string `json:"recvID"`
GroupID *string `json:"groupID"`
ClientMsgID *string `json:"clientMsgID"`
ServerMsgID *string `json:"serverMsgID"`
SenderPlatformID *int32 `json:"senderPlatformID"`
SenderNickname *string `json:"senderNickname"`
SenderFaceURL *string `json:"senderFaceURL"`
SessionType *int32 `json:"sessionType"`
MsgFrom *int32 `json:"msgFrom"`
ContentType *int32 `json:"contentType"`
Status *int32 `json:"status"`
Options *map[string]bool `json:"options"`
OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"`
AtUserIDList *[]string `json:"atUserIDList"`
MsgDataList *[]byte `json:"msgDataList"`
AttachedInfo *string `json:"attachedInfo"`
Ex *string `json:"ex"`
}
type CallbackBeforeSetMessageReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand `json:"callbackCommand"`
ConversationID string `json:"conversationID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
ReactionExtensionList map[string]*sdkws.KeyValue `json:"reactionExtensionList"`
ClientMsgID string `json:"clientMsgID"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackBeforeSetMessageReactionExtResp struct {
CommonCallbackResp
ResultReactionExtensionList []*msg.KeyValueResp `json:"resultReactionExtensionList"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackDeleteMessageReactionExtReq struct {
CallbackCommand `json:"callbackCommand"`
OperationID string `json:"operationID"`
ConversationID string `json:"conversationID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
ReactionExtensionList []*sdkws.KeyValue `json:"reactionExtensionList"`
ClientMsgID string `json:"clientMsgID"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackDeleteMessageReactionExtResp struct {
CommonCallbackResp
ResultReactionExtensionList []*msg.KeyValueResp `json:"resultReactionExtensionList"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackGetMessageListReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand `json:"callbackCommand"`
ConversationID string `json:"conversationID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
TypeKeyList []string `json:"typeKeyList"`
//MessageKeyList []*msg.GetMessageListReactionExtensionsReq_MessageReactionKey `json:"messageKeyList"`
}
type CallbackGetMessageListReactionExtResp struct {
CommonCallbackResp
MessageResultList []*msg.SingleMessageExtensionResult `json:"messageResultList"`
}
type CallbackAddMessageReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand `json:"callbackCommand"`
ConversationID string `json:"conversationID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
ReactionExtensionList map[string]*sdkws.KeyValue `json:"reactionExtensionList"`
ClientMsgID string `json:"clientMsgID"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackAddMessageReactionExtResp struct {
CommonCallbackResp
ResultReactionExtensionList []*msg.KeyValueResp `json:"resultReactionExtensionList"`
IsReact bool `json:"isReact"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
+32
View File
@@ -0,0 +1,32 @@
package callbackstruct
type CallbackUserOnlineReq struct {
UserStatusCallbackReq
//Token string `json:"token"`
Seq int64 `json:"seq"`
IsAppBackground bool `json:"isAppBackground"`
ConnID string `json:"connID"`
}
type CallbackUserOnlineResp struct {
CommonCallbackResp
}
type CallbackUserOfflineReq struct {
UserStatusCallbackReq
Seq int64 `json:"seq"`
ConnID string `json:"connID"`
}
type CallbackUserOfflineResp struct {
CommonCallbackResp
}
type CallbackUserKickOffReq struct {
UserStatusCallbackReq
Seq int64 `json:"seq"`
}
type CallbackUserKickOffResp struct {
CommonCallbackResp
}
+39
View File
@@ -0,0 +1,39 @@
package callbackstruct
import common "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
type CallbackBeforePushReq struct {
UserStatusBatchCallbackReq
*common.OfflinePushInfo
ClientMsgID string `json:"clientMsgID"`
SendID string `json:"sendID"`
GroupID string `json:"groupID"`
ContentType int32 `json:"contentType"`
SessionType int32 `json:"sessionType"`
AtUserIDs []string `json:"atUserIDList"`
Content string `json:"content"`
}
type CallbackBeforePushResp struct {
CommonCallbackResp
UserIDs []string `json:"userIDList"`
OfflinePushInfo *common.OfflinePushInfo `json:"offlinePushInfo"`
}
type CallbackBeforeSuperGroupOnlinePushReq struct {
UserStatusBaseCallback
ClientMsgID string `json:"clientMsgID"`
SendID string `json:"sendID"`
GroupID string `json:"groupID"`
ContentType int32 `json:"contentType"`
SessionType int32 `json:"sessionType"`
AtUserIDs []string `json:"atUserIDList"`
Content string `json:"content"`
Seq int64 `json:"seq"`
}
type CallbackBeforeSuperGroupOnlinePushResp struct {
CommonCallbackResp
UserIDs []string `json:"userIDList"`
OfflinePushInfo *common.OfflinePushInfo `json:"offlinePushInfo"`
}
-10
View File
@@ -1,10 +0,0 @@
package cms_api_struct
type AdminLoginRequest struct {
AdminName string `json:"admin_name" binding:"required"`
Secret string `json:"secret" binding:"required"`
}
type AdminLoginResponse struct {
Token string `json:"token"`
}
-11
View File
@@ -1,11 +0,0 @@
package cms_api_struct
type RequestPagination struct {
PageNumber int `form:"page_number" binding:"required"`
ShowNumber int `form:"show_number" binding:"required"`
}
type ResponsePagination struct {
CurrentPage int `json:"current_number" binding:"required"`
ShowNumber int `json:"show_number" binding:"required"`
}
-144
View File
@@ -1,144 +0,0 @@
package cms_api_struct
type GroupResponse struct {
GroupName string `json:"group_name"`
GroupID string `json:"group_id"`
GroupMasterName string `json:"group_master_name"`
GroupMasterId string `json:"group_master_id"`
CreateTime string `json:"create_time"`
IsBanChat bool `json:"is_ban_chat"`
IsBanPrivateChat bool `json:"is_ban_private_chat"`
ProfilePhoto string `json:"profile_photo"`
}
type GetGroupByIdRequest struct {
GroupId string `form:"group_id" binding:"required"`
}
type GetGroupByIdResponse struct {
GroupResponse
}
type GetGroupRequest struct {
GroupName string `form:"group_name" binding:"required"`
RequestPagination
}
type GetGroupResponse struct {
Groups []GroupResponse `json:"groups"`
GroupNums int `json:"group_nums"`
ResponsePagination
}
type GetGroupsRequest struct {
RequestPagination
}
type GetGroupsResponse struct {
Groups []GroupResponse `json:"groups"`
GroupNums int `json:"group_nums"`
ResponsePagination
}
type CreateGroupRequest struct {
GroupName string `json:"group_name" binding:"required"`
GroupMasterId string `json:"group_master_id" binding:"required"`
GroupMembers []string `json:"group_members" binding:"required"`
}
type CreateGroupResponse struct {
}
type SetGroupMasterRequest struct {
GroupId string `json:"group_id" binding:"required"`
UserId string `json:"user_id" binding:"required"`
}
type SetGroupMasterResponse struct {
}
type SetGroupMemberRequest struct {
GroupId string `json:"group_id" binding:"required"`
UserId string `json:"user_id" binding:"required"`
}
type SetGroupMemberRespones struct {
}
type BanGroupChatRequest struct {
GroupId string `json:"group_id" binding:"required"`
}
type BanGroupChatResponse struct {
}
type BanPrivateChatRequest struct {
GroupId string `json:"group_id" binding:"required"`
}
type BanPrivateChatResponse struct {
}
type DeleteGroupRequest struct {
GroupId string `json:"group_id" binding:"required"`
}
type DeleteGroupResponse struct {
}
type GetGroupMembersRequest struct {
GroupId string `form:"group_id" binding:"required"`
UserName string `form:"user_name"`
RequestPagination
}
type GroupMemberResponse struct {
MemberPosition int `json:"member_position"`
MemberNickName string `json:"member_nick_name"`
MemberId string `json:"member_id"`
JoinTime string `json:"join_time"`
}
type GetGroupMembersResponse struct {
GroupMembers []GroupMemberResponse `json:"group_members"`
ResponsePagination
MemberNums int `json:"member_nums"`
}
type GroupMemberRequest struct {
GroupId string `json:"group_id" binding:"required"`
Members []string `json:"members" binding:"required"`
}
type GroupMemberOperateResponse struct {
Success []string `json:"success"`
Failed []string `json:"failed"`
}
type AddGroupMembersRequest struct {
GroupMemberRequest
}
type AddGroupMembersResponse struct {
GroupMemberOperateResponse
}
type RemoveGroupMembersRequest struct {
GroupMemberRequest
}
type RemoveGroupMembersResponse struct {
GroupMemberOperateResponse
}
type AlterGroupInfoRequest struct {
GroupID string `json:"group_id"`
GroupName string `json:"group_name"`
Notification string `json:"notification"`
Introduction string `json:"introduction"`
ProfilePhoto string `json:"profile_photo"`
GroupType int `json:"group_type"`
}
type AlterGroupInfoResponse struct {
}
-50
View File
@@ -1,50 +0,0 @@
package cms_api_struct
type BroadcastRequest struct {
Message string `json:"message"`
}
type BroadcastResponse struct {
}
type MassSendMassageRequest struct {
Message string `json:"message"`
Users []string `json:"users"`
}
type MassSendMassageResponse struct {
}
type GetChatLogsRequest struct {
SessionType int `form:"session_type"`
ContentType int `form:"content_type"`
Content string `form:"content"`
UserId string `form:"user_id"`
GroupId string `form:"group_id"`
Date string `form:"date"`
RequestPagination
}
type ChatLog struct {
SessionType int `json:"session_type"`
ContentType int `json:"content_type"`
SenderNickName string `json:"sender_nick_name"`
SenderId string `json:"sender_id"`
SearchContent string `json:"search_content"`
WholeContent string `json:"whole_content"`
ReceiverNickName string `json:"receiver_nick_name,omitempty"`
ReceiverID string `json:"receiver_id,omitempty"`
GroupName string `json:"group_name,omitempty"`
GroupId string `json:"group_id,omitempty"`
Date string `json:"date"`
}
type GetChatLogsResponse struct {
ChatLogs []ChatLog `json:"chat_logs"`
ChatLogsNum int `json:"log_nums"`
ResponsePagination
}
-25
View File
@@ -1,25 +0,0 @@
package cms_api_struct
type GetStaffsResponse struct {
StaffsList []struct {
ProfilePhoto string `json:"profile_photo"`
NickName string `json:"nick_name"`
StaffId int `json:"staff_id"`
Position string `json:"position"`
EntryTime string `json:"entry_time"`
} `json:"staffs_list"`
}
type GetOrganizationsResponse struct {
OrganizationList []struct {
OrganizationId int `json:"organization_id"`
OrganizationName string `json:"organization_name"`
} `json:"organization_list"`
}
type SquadResponse struct {
SquadList []struct {
SquadId int `json:"squad_id"`
SquadName string `json:"squad_name"`
} `json:"squad_list"`
}
-89
View File
@@ -1,89 +0,0 @@
package cms_api_struct
type GetStatisticsRequest struct {
From string `form:"from" binding:"required"`
To string `form:"to" binding:"required"`
}
type GetMessageStatisticsRequest struct {
GetStatisticsRequest
}
type GetMessageStatisticsResponse struct {
PrivateMessageNum int `json:"private_message_num"`
GroupMessageNum int `json:"group_message_num"`
PrivateMessageNumList []struct {
Date string `json:"date"`
MessageNum int `json:"message_num"`
} `json:"private_message_num_list"`
GroupMessageNumList []struct {
Date string `json:"date"`
MessageNum int `json:"message_num"`
} `json:"group_message_num_list"`
}
type GetUserStatisticsRequest struct {
GetStatisticsRequest
}
type GetUserStatisticsResponse struct {
IncreaseUserNum int `json:"increase_user_num"`
ActiveUserNum int `json:"active_user_num"`
TotalUserNum int `json:"total_user_num"`
IncreaseUserNumList []struct {
Date string `json:"date"`
IncreaseUserNum int `json:"increase_user_num"`
} `json:"increase_user_num_list"`
ActiveUserNumList []struct {
Date string `json:"date"`
ActiveUserNum int `json:"active_user_num"`
} `json:"active_user_num_list"`
TotalUserNumList []struct {
Date string `json:"date"`
TotalUserNum int `json:"total_user_num"`
} `json:"total_user_num_list"`
}
type GetGroupStatisticsRequest struct {
GetStatisticsRequest
}
// 群聊统计
type GetGroupStatisticsResponse struct {
IncreaseGroupNum int `json:"increase_group_num"`
TotalGroupNum int `json:"total_group_num"`
IncreaseGroupNumList []struct {
Date string `json:"date"`
IncreaseGroupNum int `json:"increase_group_num"`
} `json:"increase_group_num_list"`
TotalGroupNumList []struct {
Date string `json:"date"`
TotalGroupNum int `json:"total_group_num"`
} `json:"total_group_num_list"`
}
type GetActiveUserRequest struct {
GetStatisticsRequest
// RequestPagination
}
type GetActiveUserResponse struct {
ActiveUserList []struct {
NickName string `json:"nick_name"`
UserId string `json:"user_id"`
MessageNum int `json:"message_num"`
} `json:"active_user_list"`
}
type GetActiveGroupRequest struct {
GetStatisticsRequest
// RequestPagination
}
type GetActiveGroupResponse struct {
ActiveGroupList []struct {
GroupName string `json:"group_name"`
GroupId string `json:"group_id"`
MessageNum int `json:"message_num"`
} `json:"active_group_list"`
}
-110
View File
@@ -1,110 +0,0 @@
package cms_api_struct
type UserResponse struct {
ProfilePhoto string `json:"profile_photo"`
Nickname string `json:"nick_name"`
UserId string `json:"user_id"`
CreateTime string `json:"create_time,omitempty"`
IsBlock bool `json:"is_block"`
}
type GetUserRequest struct {
UserId string `form:"user_id" binding:"required"`
}
type GetUserResponse struct {
UserResponse
}
type GetUsersRequest struct {
RequestPagination
}
type GetUsersResponse struct {
Users []*UserResponse `json:"users"`
ResponsePagination
UserNums int32 `json:"user_nums"`
}
type GetUsersByNameRequest struct {
UserName string `form:"user_name" binding:"required"`
RequestPagination
}
type GetUsersByNameResponse struct {
Users []*UserResponse `json:"users"`
ResponsePagination
UserNums int32 `json:"user_nums"`
}
type ResignUserRequest struct {
UserId string `json:"user_id"`
}
type ResignUserResponse struct {
}
type AlterUserRequest struct {
UserId string `json:"user_id" binding:"required"`
Nickname string `json:"nickname"`
PhoneNumber int `json:"phone_number" validate:"len=11"`
Email string `json:"email"`
}
type AlterUserResponse struct {
}
type AddUserRequest struct {
PhoneNumber string `json:"phone_number" binding:"required"`
UserId string `json:"user_id" binding:"required"`
Name string `json:"name" binding:"required"`
}
type AddUserResponse struct {
}
type BlockUser struct {
UserResponse
BeginDisableTime string `json:"begin_disable_time"`
EndDisableTime string `json:"end_disable_time"`
}
type BlockUserRequest struct {
UserId string `json:"user_id" binding:"required"`
EndDisableTime string `json:"end_disable_time" binding:"required"`
}
type BlockUserResponse struct {
}
type UnblockUserRequest struct {
UserId string `json:"user_id" binding:"required"`
}
type UnBlockUserResponse struct {
}
type GetBlockUsersRequest struct {
RequestPagination
}
type GetBlockUsersResponse struct {
BlockUsers []BlockUser `json:"block_users"`
ResponsePagination
UserNums int32 `json:"user_nums"`
}
type GetBlockUserRequest struct {
UserId string `form:"user_id" binding:"required"`
}
type GetBlockUserResponse struct {
BlockUser
}
type DeleteUserRequest struct {
UserId string `json:"user_id" binding:"required"`
}
type DeleteUserResponse struct {
}
+17
View File
@@ -0,0 +1,17 @@
package cmd
import "github.com/spf13/cobra"
type ApiCmd struct {
*RootCmd
}
func NewApiCmd() *ApiCmd {
return &ApiCmd{NewRootCmd("api")}
}
func (a *ApiCmd) AddApi(f func(port int) error) {
a.Command.RunE = func(cmd *cobra.Command, args []string) error {
return f(a.getPortFlag(cmd))
}
}
+22
View File
@@ -0,0 +1,22 @@
package cmd
import "github.com/spf13/cobra"
type CronTaskCmd struct {
*RootCmd
}
func NewCronTaskCmd() *CronTaskCmd {
return &CronTaskCmd{NewRootCmd("cronTask")}
}
func (c *CronTaskCmd) addRunE(f func() error) {
c.Command.RunE = func(cmd *cobra.Command, args []string) error {
return f()
}
}
func (c *CronTaskCmd) Exec(f func() error) error {
c.addRunE(f)
return c.Execute()
}
+36
View File
@@ -0,0 +1,36 @@
package cmd
import (
"github.com/OpenIMSDK/Open-IM-Server/internal/msggateway"
//"github.com/OpenIMSDK/Open-IM-Server/internal/msggateway"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/spf13/cobra"
)
type MsgGatewayCmd struct {
*RootCmd
}
func NewMsgGatewayCmd() MsgGatewayCmd {
return MsgGatewayCmd{NewRootCmd("msgGateway")}
}
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, _ := cmd.Flags().GetInt(constant.FlagWsPort)
return port
}
func (m *MsgGatewayCmd) addRunE() {
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
return msggateway.RunWsAndServer(m.getPortFlag(cmd), m.getWsPortFlag(cmd), m.getPrometheusPortFlag(cmd))
}
}
func (m *MsgGatewayCmd) Exec() error {
m.addRunE()
return m.Execute()
}
+25
View File
@@ -0,0 +1,25 @@
package cmd
import (
"github.com/OpenIMSDK/Open-IM-Server/internal/msgtransfer"
"github.com/spf13/cobra"
)
type MsgTransferCmd struct {
*RootCmd
}
func NewMsgTransferCmd() MsgTransferCmd {
return MsgTransferCmd{NewRootCmd("msgTransfer")}
}
func (m *MsgTransferCmd) addRunE() {
m.Command.RunE = func(cmd *cobra.Command, args []string) error {
return msgtransfer.StartTransfer(m.getPrometheusPortFlag(cmd))
}
}
func (m *MsgTransferCmd) Exec() error {
m.addRunE()
return m.Execute()
}
+170
View File
@@ -0,0 +1,170 @@
package cmd
import (
"github.com/OpenIMSDK/Open-IM-Server/internal/tools"
"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) getUserIDFlag(cmdLines *cobra.Command) string {
userID, _ := cmdLines.Flags().GetString("userID")
return userID
}
func (m *MsgUtilsCmd) AddFixAllFlag() {
m.Command.PersistentFlags().BoolP("fixAll", "f", false, "openIM fix all seqs")
}
func (m *MsgUtilsCmd) getFixAllFlag(cmdLines *cobra.Command) bool {
fixAll, _ := cmdLines.Flags().GetBool("fixAll")
return fixAll
}
func (m *MsgUtilsCmd) AddClearAllFlag() {
m.Command.PersistentFlags().BoolP("clearAll", "c", false, "openIM clear all seqs")
}
func (m *MsgUtilsCmd) getClearAllFlag(cmdLines *cobra.Command) bool {
clearAll, _ := cmdLines.Flags().GetBool("clearAll")
return clearAll
}
func (m *MsgUtilsCmd) AddSuperGroupIDFlag() {
m.Command.PersistentFlags().StringP("superGroupID", "g", "", "openIM superGroupID")
}
func (m *MsgUtilsCmd) getSuperGroupIDFlag(cmdLines *cobra.Command) string {
superGroupID, _ := cmdLines.Flags().GetString("superGroupID")
return superGroupID
}
func (m *MsgUtilsCmd) AddBeginSeqFlag() {
m.Command.PersistentFlags().Int64P("beginSeq", "b", 0, "openIM beginSeq")
}
func (m *MsgUtilsCmd) getBeginSeqFlag(cmdLines *cobra.Command) int64 {
beginSeq, _ := cmdLines.Flags().GetInt64("beginSeq")
return beginSeq
}
func (m *MsgUtilsCmd) AddLimitFlag() {
m.Command.PersistentFlags().Int64P("limit", "l", 0, "openIM limit")
}
func (m *MsgUtilsCmd) getLimitFlag(cmdLines *cobra.Command) int64 {
limit, _ := cmdLines.Flags().GetInt64("limit")
return limit
}
func (m *MsgUtilsCmd) Execute() error {
return m.Command.Execute()
}
func NewMsgUtilsCmd(use, short string, args cobra.PositionalArgs) *MsgUtilsCmd {
return &MsgUtilsCmd{
Command: cobra.Command{
Use: use,
Short: short,
Args: args,
},
}
}
type GetCmd struct {
*MsgUtilsCmd
}
func NewGetCmd() *GetCmd {
return &GetCmd{
NewMsgUtilsCmd("get [resource]", "get action", cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs)),
}
}
type FixCmd struct {
*MsgUtilsCmd
}
func NewFixCmd() *FixCmd {
return &FixCmd{
NewMsgUtilsCmd("fix [resource]", "fix action", cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs)),
}
}
type ClearCmd struct {
*MsgUtilsCmd
}
func NewClearCmd() *ClearCmd {
return &ClearCmd{
NewMsgUtilsCmd("clear [resource]", "clear action", cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs)),
}
}
type SeqCmd struct {
*MsgUtilsCmd
}
func NewSeqCmd() *SeqCmd {
seqCmd := &SeqCmd{
NewMsgUtilsCmd("seq", "seq", nil),
}
return seqCmd
}
func (s *SeqCmd) GetSeqCmd() *cobra.Command {
s.Command.Run = func(cmdLines *cobra.Command, args []string) {
_, err := tools.InitMsgTool()
if err != nil {
panic(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
}
func (s *SeqCmd) FixSeqCmd() *cobra.Command {
return &s.Command
}
type MsgCmd struct {
*MsgUtilsCmd
}
func NewMsgCmd() *MsgCmd {
msgCmd := &MsgCmd{
NewMsgUtilsCmd("msg", "msg", nil),
}
return msgCmd
}
func (m *MsgCmd) GetMsgCmd() *cobra.Command {
return &m.Command
}
func (m *MsgCmd) ClearMsgCmd() *cobra.Command {
return &m.Command
}
+81
View File
@@ -0,0 +1,81 @@
package cmd
import (
"fmt"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/spf13/cobra"
)
type RootCmd struct {
Command cobra.Command
Name string
port int
prometheusPort int
}
func NewRootCmd(name string) (rootCmd *RootCmd) {
rootCmd = &RootCmd{Name: name}
c := cobra.Command{
Use: "start",
Short: fmt.Sprintf(`Start %s server`, name),
Long: fmt.Sprintf(`Start %s server`, name),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := rootCmd.getConfFromCmdAndInit(cmd); err != nil {
panic(err)
}
if err := log.InitFromConfig("OpenIM.log.all", name, config.Config.Log.RemainLogLevel, config.Config.Log.IsStdout, config.Config.Log.IsJson, config.Config.Log.StorageLocation, config.Config.Log.RemainRotationCount); err != nil {
panic(err)
}
return nil
},
}
rootCmd.Command = c
rootCmd.addConfFlag()
return rootCmd
}
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, _ := cmd.Flags().GetInt(constant.FlagPort)
return port
}
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, _ := cmd.Flags().GetInt(constant.FlagPrometheusPort)
return port
}
func (r *RootCmd) GetPrometheusPortFlag() int {
return r.prometheusPort
}
func (r *RootCmd) getConfFromCmdAndInit(cmdLines *cobra.Command) error {
configFolderPath, _ := cmdLines.Flags().GetString(constant.FlagConf)
return config.InitConfig(configFolderPath)
}
func (r *RootCmd) Execute() error {
return r.Command.Execute()
}
func (r *RootCmd) AddCommand(cmds ...*cobra.Command) {
r.Command.AddCommand(cmds...)
}
+34
View File
@@ -0,0 +1,34 @@
package cmd
import (
"errors"
"github.com/OpenIMSDK/Open-IM-Server/pkg/discoveryregistry"
"github.com/OpenIMSDK/Open-IM-Server/pkg/startrpc"
"github.com/spf13/cobra"
"google.golang.org/grpc"
)
type RpcCmd struct {
*RootCmd
}
func NewRpcCmd(name string) *RpcCmd {
authCmd := &RpcCmd{NewRootCmd(name)}
return authCmd
}
func (a *RpcCmd) Exec() error {
a.Command.Run = func(cmd *cobra.Command, args []string) {
a.port = a.getPortFlag(cmd)
a.prometheusPort = a.getPrometheusPortFlag(cmd)
}
return a.Execute()
}
func (a *RpcCmd) StartSvr(name string, rpcFn func(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error) error {
if a.GetPortFlag() == 0 {
return errors.New("port is required")
}
return startrpc.Start(a.GetPortFlag(), name, a.GetPrometheusPortFlag(), rpcFn)
}
+246 -405
View File
@@ -1,49 +1,123 @@
package config
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
_ "embed"
)
var (
_, b, _, _ = runtime.Caller(0)
// Root folder of this project
Root = filepath.Join(filepath.Dir(b), "../../..")
)
//go:embed version
var Version string
var Config config
type callBackConfig struct {
Enable bool `yaml:"enable"`
CallbackTimeOut int `yaml:"callbackTimeOut"`
CallbackFailedContinue bool `yaml:"callbackFailedContinue"`
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 presistent
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 config struct {
ServerIP string `yaml:"serverip"`
ServerVersion string `yaml:"serverversion"`
Api struct {
GinPort []int `yaml:"openImApiPort"`
}
CmsApi struct {
GinPort []int `yaml:"openImCmsApiPort"`
}
Sdk struct {
WsPort []int `yaml:"openImSdkWsPort"`
}
Credential struct {
Zookeeper struct {
Schema string `yaml:"schema"`
ZkAddr []string `yaml:"address"`
Username string `yaml:"username"`
Password string `yaml:"password"`
} `yaml:"zookeeper"`
Mysql struct {
Address []string `yaml:"address"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Database string `yaml:"database"`
MaxOpenConn int `yaml:"maxOpenConn"`
MaxIdleConn int `yaml:"maxIdleConn"`
MaxLifeTime int `yaml:"maxLifeTime"`
LogLevel int `yaml:"logLevel"`
SlowThreshold int `yaml:"slowThreshold"`
} `yaml:"mysql"`
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 {
Address []string `yaml:"address"`
Username string `yaml:"username"`
Password string `yaml:"password"`
} `yaml:"redis"`
Kafka struct {
Username string `yaml:"username"`
Password string `yaml:"password"`
Addr []string `yaml:"addr"`
LatestMsgToRedis struct {
Topic string `yaml:"topic"`
} `yaml:"latestMsgToRedis"`
MsgToMongo struct {
Topic string `yaml:"topic"`
} `yaml:"offlineMsgToMongo"`
MsgToPush struct {
Topic string `yaml:"topic"`
} `yaml:"msgToPush"`
MsgToModify struct {
Topic string `yaml:"topic"`
} `yaml:"msgToModify"`
ConsumerGroupID struct {
MsgToRedis string `yaml:"msgToRedis"`
MsgToMongo string `yaml:"msgToMongo"`
MsgToMySql string `yaml:"msgToMySql"`
MsgToPush string `yaml:"msgToPush"`
MsgToModify string `yaml:"msgToModify"`
} `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 {
TempBucket string `yaml:"tempBucket"`
DataBucket string `yaml:"dataBucket"`
Location string `yaml:"location"`
Endpoint string `yaml:"endpoint"`
AccessKeyID string `yaml:"accessKeyID"`
SecretAccessKey string `yaml:"secretAccessKey"`
IsDistributedMod bool `yaml:"isDistributedMod"`
} `yaml:"minio"`
Tencent struct {
AppID string `yaml:"appID"`
Region string `yaml:"region"`
Bucket string `yaml:"bucket"`
SecretID string `yaml:"secretID"`
SecretKey string `yaml:"secretKey"`
}
} `yaml:"tencent"`
Ali struct {
RegionID string `yaml:"regionID"`
AccessKeyID string `yaml:"accessKeyID"`
@@ -54,409 +128,176 @@ type config struct {
FinalHost string `yaml:"finalHost"`
StsDurationSeconds int64 `yaml:"stsDurationSeconds"`
OssRoleArn string `yaml:"OssRoleArn"`
}
Minio struct {
Bucket string `yaml:"bucket"`
Location string `yaml:"location"`
Endpoint string `yaml:"endpoint"`
AccessKeyID string `yaml:"accessKeyID"`
SecretAccessKey string `yaml:"secretAccessKey"`
EndpointInner string `yaml:"endpointInner"`
EndpointInnerEnable bool `yaml:"endpointInnerEnable"`
} `yaml:"minio"`
}
} `yaml:"ali"`
Aws struct {
AccessKeyID string `yaml:"accessKeyID"`
AccessKeySecret string `yaml:"accessKeySecret"`
Region string `yaml:"region"`
Bucket string `yaml:"bucket"`
FinalHost string `yaml:"finalHost"`
RoleArn string `yaml:"roleArn"`
ExternalId string `yaml:"externalId"`
RoleSessionName string `yaml:"roleSessionName"`
} `yaml:"aws"`
} `yaml:"object"`
Mysql struct {
DBAddress []string `yaml:"dbMysqlAddress"`
DBUserName string `yaml:"dbMysqlUserName"`
DBPassword string `yaml:"dbMysqlPassword"`
DBDatabaseName string `yaml:"dbMysqlDatabaseName"`
DBTableName string `yaml:"DBTableName"`
DBMsgTableNum int `yaml:"dbMsgTableNum"`
DBMaxOpenConns int `yaml:"dbMaxOpenConns"`
DBMaxIdleConns int `yaml:"dbMaxIdleConns"`
DBMaxLifeTime int `yaml:"dbMaxLifeTime"`
}
Mongo struct {
DBUri string `yaml:"dbUri"` // 当dbUri值不为空则直接使用该值
DBAddress []string `yaml:"dbAddress"`
DBDirect bool `yaml:"dbDirect"`
DBTimeout int `yaml:"dbTimeout"`
DBDatabase string `yaml:"dbDatabase"`
DBSource string `yaml:"dbSource"`
DBUserName string `yaml:"dbUserName"`
DBPassword string `yaml:"dbPassword"`
DBMaxPoolSize int `yaml:"dbMaxPoolSize"`
DBRetainChatRecords int `yaml:"dbRetainChatRecords"`
}
Redis struct {
DBAddress string `yaml:"dbAddress"`
DBMaxIdle int `yaml:"dbMaxIdle"`
DBMaxActive int `yaml:"dbMaxActive"`
DBIdleTimeout int `yaml:"dbIdleTimeout"`
DBPassWord string `yaml:"dbPassWord"`
}
RpcPort struct {
OpenImUserPort []int `yaml:"openImUserPort"`
openImFriendPort []int `yaml:"openImFriendPort"`
RpcMessagePort []int `yaml:"rpcMessagePort"`
RpcPushMessagePort []int `yaml:"rpcPushMessagePort"`
OpenImGroupPort []int `yaml:"openImGroupPort"`
RpcModifyUserInfoPort []int `yaml:"rpcModifyUserInfoPort"`
RpcGetTokenPort []int `yaml:"rpcGetTokenPort"`
}
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 {
OpenImStatisticsName string `yaml:"OpenImStatisticsName"`
OpenImUserName string `yaml:"openImUserName"`
OpenImFriendName string `yaml:"openImFriendName"`
OpenImOfflineMessageName string `yaml:"openImOfflineMessageName"`
OpenImPushName string `yaml:"openImPushName"`
OpenImOnlineMessageRelayName string `yaml:"openImOnlineMessageRelayName"`
OpenImGroupName string `yaml:"openImGroupName"`
OpenImAuthName string `yaml:"openImAuthName"`
OpenImMessageCMSName string `yaml:"openImMessageCMSName"`
OpenImAdminCMSName string `yaml:"openImAdminCMSName"`
OpenImOfficeName string `yaml:"openImOfficeName"`
OpenImOrganizationName string `yaml:"openImOrganizationName"`
OpenImConversationName string `yaml:"openImConversationName"`
}
Etcd struct {
EtcdSchema string `yaml:"etcdSchema"`
EtcdAddr []string `yaml:"etcdAddr"`
}
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 int `yaml:"rotationTime"`
RemainRotationCount uint `yaml:"remainRotationCount"`
RemainLogLevel uint `yaml:"remainLogLevel"`
ElasticSearchSwitch bool `yaml:"elasticSearchSwitch"`
ElasticSearchAddr []string `yaml:"elasticSearchAddr"`
ElasticSearchUser string `yaml:"elasticSearchUser"`
ElasticSearchPassword string `yaml:"elasticSearchPassword"`
}
ModuleName struct {
LongConnSvrName string `yaml:"longConnSvrName"`
MsgTransferName string `yaml:"msgTransferName"`
PushName string `yaml:"pushName"`
}
StorageLocation string `yaml:"storageLocation"`
RotationTime int `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 {
WebsocketPort []int `yaml:"openImWsPort"`
OpenImWsPort []int `yaml:"openImWsPort"`
WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"`
WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"`
WebsocketTimeOut int `yaml:"websocketTimeOut"`
}
WebsocketTimeout int `yaml:"websocketTimeout"`
} `yaml:"longConnSvr"`
Push struct {
Tpns struct {
Ios struct {
AccessID string `yaml:"accessID"`
SecretKey string `yaml:"secretKey"`
}
Android struct {
AccessID string `yaml:"accessID"`
SecretKey string `yaml:"secretKey"`
}
Enable bool `yaml:"enable"`
}
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"`
Enable bool `yaml:"enable"`
}
Getui struct {
PushUrl string `yaml:"pushUrl"`
AppKey string `yaml:"appKey"`
Enable bool `yaml:"enable"`
Intent string `yaml:"intent"`
MasterSecret string `yaml:"masterSecret"`
}
} `yaml:"jpns"`
}
Manager struct {
AppManagerUid []string `yaml:"appManagerUid"`
Secrets []string `yaml:"secrets"`
AppSysNotificationName string `yaml:"appSysNotificationName"`
}
UserID []string `yaml:"userID"`
Nickname []string `yaml:"nickname"`
} `yaml:"manager"`
Kafka struct {
Ws2mschat struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
Ms2pschat struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
ConsumerGroupID struct {
MsgToMongo string `yaml:"msgToMongo"`
MsgToMySql string `yaml:"msgToMySql"`
MsgToPush string `yaml:"msgToPush"`
}
}
Secret string `yaml:"secret"`
MultiLoginPolicy int `yaml:"multiloginpolicy"`
ChatPersistenceMysql bool `yaml:"chatPersistenceMysql"`
TokenPolicy struct {
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"`
TokenPolicy struct {
AccessSecret string `yaml:"accessSecret"`
AccessExpire int64 `yaml:"accessExpire"`
}
} `yaml:"tokenPolicy"`
MessageVerify struct {
FriendVerify bool `yaml:"friendVerify"`
}
FriendVerify *bool `yaml:"friendVerify"`
} `yaml:"messageVerify"`
IOSPush struct {
PushSound string `yaml:"pushSound"`
BadgeCount bool `yaml:"badgeCount"`
Production bool `yaml:"production"`
}
} `yaml:"iosPush"`
Callback struct {
CallbackUrl string `yaml:"callbackUrl"`
CallbackBeforeSendSingleMsg callBackConfig `yaml:"callbackbeforeSendSingleMsg"`
CallbackAfterSendSingleMsg callBackConfig `yaml:"callbackAfterSendSingleMsg"`
CallbackBeforeSendGroupMsg callBackConfig `yaml:"callbackBeforeSendGroupMsg"`
CallbackAfterSendGroupMsg callBackConfig `yaml:"callbackAfterSendGroupMsg"`
CallbackWordFilter callBackConfig `yaml:"callbackWordFilter"`
CallbackUrl string `yaml:"url"`
CallbackBeforeSendSingleMsg CallBackConfig `yaml:"beforeSendSingleMsg"`
CallbackAfterSendSingleMsg CallBackConfig `yaml:"afterSendSingleMsg"`
CallbackBeforeSendGroupMsg CallBackConfig `yaml:"beforeSendGroupMsg"`
CallbackAfterSendGroupMsg CallBackConfig `yaml:"afterSendGroupMsg"`
CallbackMsgModify CallBackConfig `yaml:"msgModify"`
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"`
CallbackBeforeCreateGroup CallBackConfig `yaml:"beforeCreateGroup"`
CallbackBeforeMemberJoinGroup CallBackConfig `yaml:"beforeMemberJoinGroup"`
CallbackBeforeSetGroupMemberInfo CallBackConfig `yaml:"beforeSetGroupMemberInfo"`
} `yaml:"callback"`
Notification struct {
///////////////////////group/////////////////////////////
GroupCreated struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupCreated"`
GroupInfoSet struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupInfoSet"`
JoinGroupApplication struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"joinGroupApplication"`
MemberQuit struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"memberQuit"`
GroupApplicationAccepted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupApplicationAccepted"`
GroupApplicationRejected struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupApplicationRejected"`
GroupOwnerTransferred struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupOwnerTransferred"`
MemberKicked struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"memberKicked"`
MemberInvited struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"memberInvited"`
MemberEnter struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"memberEnter"`
GroupDismissed struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupDismissed"`
GroupMuted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupMuted"`
GroupCancelMuted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupCancelMuted"`
GroupMemberMuted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupMemberMuted"`
GroupMemberCancelMuted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupMemberCancelMuted"`
GroupMemberInfoSet struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"groupMemberInfoSet"`
OrganizationChanged struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"organizationChanged"`
////////////////////////user///////////////////////
UserInfoUpdated struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"userInfoUpdated"`
//////////////////////friend///////////////////////
FriendApplication struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendApplicationAdded"`
FriendApplicationApproved struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendApplicationApproved"`
FriendApplicationRejected struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendApplicationRejected"`
FriendAdded struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendAdded"`
FriendDeleted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendDeleted"`
FriendRemarkSet struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendRemarkSet"`
BlackAdded struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"blackAdded"`
BlackDeleted struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"blackDeleted"`
ConversationOptUpdate struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"conversationOptUpdate"`
ConversationSetPrivate struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips struct {
OpenTips string `yaml:"openTips"`
CloseTips string `yaml:"closeTips"`
} `yaml:"defaultTips"`
} `yaml:"conversationSetPrivate"`
WorkMomentsNotification struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"workMomentsNotification"`
JoinDepartmentNotification struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"joinDepartmentNotification"`
}
Demo struct {
Port []int `yaml:"openImDemoPort"`
AliSMSVerify struct {
AccessKeyID string `yaml:"accessKeyId"`
AccessKeySecret string `yaml:"accessKeySecret"`
SignName string `yaml:"signName"`
VerificationCodeTemplateCode string `yaml:"verificationCodeTemplateCode"`
}
SuperCode string `yaml:"superCode"`
CodeTTL int `yaml:"codeTTL"`
Mail struct {
Title string `yaml:"title"`
SenderMail string `yaml:"senderMail"`
SenderAuthorizationCode string `yaml:"senderAuthorizationCode"`
SmtpAddr string `yaml:"smtpAddr"`
SmtpPort int `yaml:"smtpPort"`
}
TestDepartMentID string `yaml:"testDepartMentID"`
ImAPIURL string `yaml:"imAPIURL"`
}
Rtc struct {
Port int `yaml:"port"`
Address string `yaml:"address"`
} `yaml:"rtc"`
}
type PConversation struct {
ReliabilityLevel int `yaml:"reliabilityLevel"`
UnreadCount bool `yaml:"unreadCount"`
Prometheus struct {
Enable bool `yaml:"enable"`
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"`
}
type POfflinePush struct {
PushSwitch bool `yaml:"switch"`
Title string `yaml:"title"`
Desc string `yaml:"desc"`
Ext string `yaml:"ext"`
}
type PDefaultTips struct {
Tips string `yaml:"tips"`
}
func init() {
//path, _ := os.Getwd()
//bytes, err := ioutil.ReadFile(path + "/config/config.yaml")
// if we cd Open-IM-Server/src/utils and run go test
// it will panic cannot find config/config.yaml
cfgName := os.Getenv("CONFIG_NAME")
if len(cfgName) == 0 {
cfgName = Root + "/config/config.yaml"
}
viper.SetConfigFile(cfgName)
err := viper.ReadInConfig()
if err != nil {
panic(err.Error())
}
bytes, err := ioutil.ReadFile(cfgName)
if err != nil {
panic(err.Error())
}
if err = yaml.Unmarshal(bytes, &Config); err != nil {
panic(err.Error())
}
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"`
//////////////////////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"`
}
+107
View File
@@ -0,0 +1,107 @@
package config
import (
"bytes"
"fmt"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/discoveryregistry"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"gopkg.in/yaml.v3"
"os"
"path/filepath"
"runtime"
)
var (
_, b, _, _ = runtime.Caller(0)
// Root folder of this project
Root = filepath.Join(filepath.Dir(b), "../../..")
)
const (
FileName = "config.yaml"
NotificationFileName = "notification.yaml"
ENV = "CONFIG_NAME"
DefaultFolderPath = "../config/"
ConfKey = "conf"
)
func GetOptionsByNotification(cfg NotificationConf) utils.Options {
opts := utils.NewOptions()
if cfg.UnreadCount {
opts = utils.WithOptions(opts, utils.WithUnreadCount(true))
}
if cfg.OfflinePush.Enable {
opts = utils.WithOptions(opts, utils.WithOfflinePush(true))
}
switch cfg.ReliabilityLevel {
case constant.UnreliableNotification:
case constant.ReliableNotificationNoMsg:
opts = utils.WithOptions(opts, utils.WithHistory(true), utils.WithPersistent())
}
opts = utils.WithOptions(opts, utils.WithSendMsg(cfg.IsSendMsg))
return opts
}
func (c *config) unmarshalConfig(config interface{}, configPath string) error {
bytes, err := os.ReadFile(configPath)
if err != nil {
return err
}
if err = yaml.Unmarshal(bytes, config); err != nil {
return err
}
return nil
}
func (c *config) initConfig(config interface{}, configName, configFolderPath string) error {
if configFolderPath == "" {
configFolderPath = DefaultFolderPath
}
configPath := filepath.Join(configFolderPath, configName)
defer func() {
fmt.Println("use config", configPath)
}()
_, err := os.Stat(configPath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
configPath = filepath.Join(Root, "config", configName)
} else {
Root = filepath.Dir(configPath)
}
return c.unmarshalConfig(config, configPath)
}
func (c *config) RegisterConf2Registry(registry discoveryregistry.SvcDiscoveryRegistry) error {
bytes, err := yaml.Marshal(Config)
if err != nil {
return err
}
return registry.RegisterConf2Registry(ConfKey, bytes)
}
func (c *config) GetConfFromRegistry(registry discoveryregistry.SvcDiscoveryRegistry) ([]byte, error) {
return registry.GetConfFromRegistry(ConfKey)
}
func InitConfig(configFolderPath string) error {
err := Config.initConfig(&Config, FileName, configFolderPath)
if err != nil {
return err
}
err = Config.initConfig(&Config.Notification, NotificationFileName, configFolderPath)
if err != nil {
return err
}
return nil
}
func EncodeConfig() []byte {
buf := bytes.NewBuffer(nil)
if err := yaml.NewEncoder(buf).Encode(Config); err != nil {
panic(err)
}
return buf.Bytes()
}
+1
View File
@@ -0,0 +1 @@
v3.0.0
+174 -97
View File
@@ -2,48 +2,33 @@ package constant
const (
//group admin
// OrdinaryMember = 0
// GroupOwner = 1
// Administrator = 2
//group application
// Application = 0
// AgreeApplication = 1
//friend related
BlackListFlag = 1
ApplicationFriendFlag = 0
FriendFlag = 1
RefuseFriendFlag = -1
//Websocket Protocol
WSGetNewestSeq = 1001
WSPullMsgBySeqList = 1002
WSSendMsg = 1003
WSSendSignalMsg = 1004
WSPushMsg = 2001
WSKickOnlineMsg = 2002
WsLogoutMsg = 2003
WSDataError = 3001
///ContentType
//UserRelated
Text = 101
Picture = 102
Voice = 103
Video = 104
File = 105
AtText = 106
Merger = 107
Card = 108
Location = 109
Custom = 110
Revoke = 111
HasReadReceipt = 112
Typing = 113
Quote = 114
Common = 200
GroupMsg = 201
Text = 101
Picture = 102
Voice = 103
Video = 104
File = 105
AtText = 106
Merger = 107
Card = 108
Location = 109
Custom = 110
Revoke = 111
Typing = 113
Quote = 114
AdvancedText = 117
CustomNotTriggerConversation = 119
CustomOnlineOnly = 120
ReactionMessageModifier = 121
ReactionMessageDeleter = 122
Common = 200
GroupMsg = 201
SignalMsg = 202
CustomNotification = 203
//SysRelated
NotificationBegin = 1000
@@ -56,8 +41,9 @@ const (
FriendRemarkSetNotification = 1206 //set_friend_remark?
BlackAddedNotification = 1207 //add_black
BlackDeletedNotification = 1208 //remove_black
FriendInfoUpdatedNotification = 1209
ConversationOptChangeNotification = 1300 // change conversation opt
ConversationChangeNotification = 1300 // change conversation opt
UserNotificationBegin = 1301
UserInfoUpdatedNotification = 1303 //SetSelfInfoTip = 204
@@ -66,22 +52,26 @@ const (
GroupNotificationBegin = 1500
GroupCreatedNotification = 1501
GroupInfoSetNotification = 1502
JoinGroupApplicationNotification = 1503
MemberQuitNotification = 1504
GroupApplicationAcceptedNotification = 1505
GroupApplicationRejectedNotification = 1506
GroupOwnerTransferredNotification = 1507
MemberKickedNotification = 1508
MemberInvitedNotification = 1509
MemberEnterNotification = 1510
GroupDismissedNotification = 1511
GroupMemberMutedNotification = 1512
GroupMemberCancelMutedNotification = 1513
GroupMutedNotification = 1514
GroupCancelMutedNotification = 1515
GroupMemberInfoSetNotification = 1516
GroupCreatedNotification = 1501
GroupInfoSetNotification = 1502
JoinGroupApplicationNotification = 1503
MemberQuitNotification = 1504
GroupApplicationAcceptedNotification = 1505
GroupApplicationRejectedNotification = 1506
GroupOwnerTransferredNotification = 1507
MemberKickedNotification = 1508
MemberInvitedNotification = 1509
MemberEnterNotification = 1510
GroupDismissedNotification = 1511
GroupMemberMutedNotification = 1512
GroupMemberCancelMutedNotification = 1513
GroupMutedNotification = 1514
GroupCancelMutedNotification = 1515
GroupMemberInfoSetNotification = 1516
GroupMemberSetToAdminNotification = 1517
GroupMemberSetToOrdinaryUserNotification = 1518
GroupInfoSetAnnouncementNotification = 1519
GroupInfoSetNameNotification = 1520
SignalingNotificationBegin = 1600
SignalingNotification = 1601
@@ -89,13 +79,24 @@ const (
SuperGroupNotificationBegin = 1650
SuperGroupUpdateNotification = 1651
MsgDeleteNotification = 1652
SuperGroupNotificationEnd = 1699
ConversationPrivateChatNotification = 1701
ConversationUnreadNotification = 1702
OrganizationChangedNotification = 1801
MsgRevokeNotification = 2101
NotificationEnd = 2000
BusinessNotificationBegin = 2000
BusinessNotification = 2001
BusinessNotificationEnd = 2099
ClearConversationNotification = 2101
DeleteMsgsNotification = 2102
HasReadReceipt = 2200
NotificationEnd = 5000
//status
MsgNormal = 1
@@ -106,9 +107,9 @@ const (
SysMsgType = 200
//SessionType
SingleChatType = 1
GroupChatType = 2
SingleChatType = 1
GroupChatType = 2
SuperGroupChatType = 3
NotificationChatType = 4
//token
NormalToken = 0
@@ -117,6 +118,7 @@ const (
ExpiredToken = 3
//MultiTerminalLogin
DefalutNotKick = 0
//Full-end login, but the same end is mutually exclusive
AllLoginButSameTermKick = 1
//Only one of the endpoints can log in
@@ -125,6 +127,8 @@ const (
WebAndOther = 3
//The PC side is mutually exclusive, and the mobile side is mutually exclusive, but the web side can be online at the same time
PcMobileAndWeb = 4
//The PC terminal can be online at the same time,but other terminal only one of the endpoints can login
PCAndOther = 5
OnlineStatus = "online"
OfflineStatus = "offline"
@@ -146,6 +150,9 @@ const (
IsNotPrivate = "notPrivate"
IsSenderConversationUpdate = "senderConversationUpdate"
IsSenderNotificationPush = "senderNotificationPush"
IsReactionFromCache = "reactionFromCache"
IsNotNotification = "isNotNotification"
IsSendMsg = "isSendMsg"
//GroupStatus
GroupOk = 0
@@ -154,8 +161,9 @@ const (
GroupStatusMuted = 3
//GroupType
NormalGroup = 0
DepartmentGroup = 1
NormalGroup = 0
SuperGroup = 1
WorkingGroup = 2
GroupBaned = 3
GroupBanPrivateChat = 4
@@ -163,21 +171,36 @@ const (
//UserJoinGroupSource
JoinByAdmin = 1
JoinByInvitation = 2
JoinBySearch = 3
JoinByQRCode = 4
//Minio
MinioDurationTimes = 3600
// verificationCode used for
VerificationCodeForRegister = 1
VerificationCodeForReset = 2
VerificationCodeForRegisterSuffix = "_forRegister"
VerificationCodeForResetSuffix = "_forReset"
//Aws
AwsDurationTimes = 3600
//callbackCommand
CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand"
CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand"
CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand"
CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand"
CallbackWordFilterCommand = "callbackWordFilterCommand"
CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand"
CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand"
CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand"
CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand"
CallbackMsgModifyCommand = "callbackMsgModifyCommand"
CallbackUserOnlineCommand = "callbackUserOnlineCommand"
CallbackUserOfflineCommand = "callbackUserOfflineCommand"
CallbackUserKickOffCommand = "callbackUserKickOffCommand"
CallbackOfflinePushCommand = "callbackOfflinePushCommand"
CallbackOnlinePushCommand = "callbackOnlinePushCommand"
CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand"
CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand"
CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand"
CallbackBeforeMemberJoinGroupCommand = "callbackBeforeMemberJoinGroupCommand"
CallbackBeforeSetGroupMemberInfoCommand = "CallbackBeforeSetGroupMemberInfoCommand"
CallbackBeforeSetMessageReactionExtensionCommand = "callbackBeforeSetMessageReactionExtensionCommand"
CallbackBeforeDeleteMessageReactionExtensionsCommand = "callbackBeforeDeleteMessageReactionExtensionsCommand"
CallbackGetMessageListReactionExtensionsCommand = "callbackGetMessageListReactionExtensionsCommand"
CallbackAddMessageListReactionExtensionsCommand = "callbackAddMessageListReactionExtensionsCommand"
//callback actionCode
ActionAllow = 0
ActionForbidden = 1
@@ -189,24 +212,44 @@ const (
OtherType = 1
VideoType = 2
ImageType = 3
// sendMsgStaus
MsgStatusNotExist = 0
MsgIsSending = 1
MsgSendSuccessed = 2
MsgSendFailed = 3
)
const (
AtAllString = "AtAllTag"
AtNormal = 0
AtMe = 1
AtAll = 2
AtAllAtMe = 3
WriteDiffusion = 0
ReadDiffusion = 1
)
const (
UnreliableNotification = 1
ReliableNotificationNoMsg = 2
ReliableNotificationMsg = 3
)
const (
AtAllString = "AtAllTag"
AtNormal = 0
AtMe = 1
AtAll = 2
AtAllAtMe = 3
GroupNotification = 4
)
var ContentType2PushContent = map[int64]string{
Picture: "[图片]",
Voice: "[语音]",
Video: "[视频]",
File: "[文件]",
Text: "你收到了一条文本消息",
AtText: "[有人@你]",
GroupMsg: "你收到一条群聊消息",
Common: "你收到一条新消息",
Picture: "[PICTURE]",
Voice: "[VOICE]",
Video: "[VIDEO]",
File: "[File]",
Text: "[TEXT]",
AtText: "[@TEXT]",
GroupMsg: "[GROUPMSG]]",
Common: "[NEWMSG]",
SignalMsg: "[SIGNALINVITE]",
}
const (
@@ -215,18 +258,19 @@ const (
FieldAttachedInfo = 3
FieldIsPrivateChat = 4
FieldGroupAtType = 5
FieldIsNotInGroup = 6
FieldEx = 7
FieldUnread = 8
FieldBurnDuration = 9
FieldHasReadSeq = 10
)
const (
AppOrdinaryUsers = 1
AppAdmin = 2
GroupOrdinaryUsers = 1
GroupOwner = 2
GroupAdmin = 3
GroupOwner = 100
GroupAdmin = 60
GroupOrdinaryUsers = 20
GroupResponseAgree = 1
GroupResponseRefuse = -1
@@ -238,10 +282,30 @@ const (
Female = 2
)
const OperationID = "operationID"
const OpUserID = "opUserID"
const ConnID = "connID"
const OpUserPlatform = "platform"
const Token = "token"
const RpcCustomHeader = "customHeader" // rpc中间件自定义ctx参数
const CheckKey = "CheckKey"
const TriggerID = "triggerID"
const RemoteAddr = "remoteAddr"
const (
UnreliableNotification = 1
ReliableNotificationNoMsg = 2
ReliableNotificationMsg = 3
BecomeFriendByImport = 1 //管理员导入
BecomeFriendByApply = 2 //申请添加
)
const (
ApplyNeedVerificationInviteDirectly = 0 // 申请需要同意 邀请直接进
AllNeedVerification = 1 //所有人进群需要验证,除了群主管理员邀请进群
Directly = 2 //直接进群
)
const (
GroupRPCRecvSize = 30
GroupRPCSendSize = 30
)
const FriendAcceptTip = "You have successfully become friends, so start chatting"
@@ -260,6 +324,19 @@ func GroupIsBanPrivateChat(status int32) bool {
return true
}
const BigVersion = "v3"
const LogFileName = "OpenIM.log"
const LocalHost = "0.0.0.0"
// flag parse
const (
FlagPort = "port"
FlagWsPort = "ws_port"
FlagPrometheusPort = "prometheus_port"
FlagConf = "config_folder_path"
)
const OpenIMCommonConfigKey = "OpenIMServerConfig"
const CallbackCommand = "command"
-102
View File
@@ -1,102 +0,0 @@
package constant
import "errors"
// key = errCode, string = errMsg
type ErrInfo struct {
ErrCode int32
ErrMsg string
}
var (
OK = ErrInfo{0, ""}
ErrServer = ErrInfo{500, "server error"}
// ErrMysql = ErrInfo{100, ""}
// ErrMongo = ErrInfo{110, ""}
// ErrRedis = ErrInfo{120, ""}
ErrParseToken = ErrInfo{700, ParseTokenMsg.Error()}
// ErrCreateToken = ErrInfo{201, "Create token failed"}
// ErrAppServerKey = ErrInfo{300, "key error"}
ErrTencentCredential = ErrInfo{400, ThirdPartyMsg.Error()}
// ErrorUserRegister = ErrInfo{600, "User registration failed"}
// ErrAccountExists = ErrInfo{601, "The account is already registered and cannot be registered again"}
// ErrUserPassword = ErrInfo{602, "User password error"}
// ErrRefreshToken = ErrInfo{605, "Failed to refresh token"}
// ErrAddFriend = ErrInfo{606, "Failed to add friends"}
// ErrAgreeToAddFriend = ErrInfo{607, "Failed to agree application"}
// ErrAddFriendToBlack = ErrInfo{608, "Failed to add friends to the blacklist"}
// ErrGetBlackList = ErrInfo{609, "Failed to get blacklist"}
// ErrDeleteFriend = ErrInfo{610, "Failed to delete friend"}
// ErrGetFriendApplyList = ErrInfo{611, "Failed to get friend application list"}
// ErrGetFriendList = ErrInfo{612, "Failed to get friend list"}
// ErrRemoveBlackList = ErrInfo{613, "Failed to remove blacklist"}
// ErrSearchUserInfo = ErrInfo{614, "Can't find the user information"}
// ErrDelAppleDeviceToken = ErrInfo{615, ""}
// ErrModifyUserInfo = ErrInfo{616, "update user some attribute failed"}
// ErrSetFriendComment = ErrInfo{617, "set friend comment failed"}
// ErrSearchUserInfoFromTheGroup = ErrInfo{618, "There is no such group or the user not in the group"}
// ErrCreateGroup = ErrInfo{619, "create group chat failed"}
// ErrJoinGroupApplication = ErrInfo{620, "Failed to apply to join the group"}
// ErrQuitGroup = ErrInfo{621, "Failed to quit the group"}
// ErrSetGroupInfo = ErrInfo{622, "Failed to set group info"}
// ErrParam = ErrInfo{700, "param failed"}
ErrTokenExpired = ErrInfo{701, TokenExpiredMsg.Error()}
ErrTokenInvalid = ErrInfo{702, TokenInvalidMsg.Error()}
ErrTokenMalformed = ErrInfo{703, TokenMalformedMsg.Error()}
ErrTokenNotValidYet = ErrInfo{704, TokenNotValidYetMsg.Error()}
ErrTokenUnknown = ErrInfo{705, TokenUnknownMsg.Error()}
ErrTokenKicked = ErrInfo{706, TokenUserKickedMsg.Error()}
ErrAccess = ErrInfo{ErrCode: 801, ErrMsg: AccessMsg.Error()}
ErrDB = ErrInfo{ErrCode: 802, ErrMsg: DBMsg.Error()}
ErrArgs = ErrInfo{ErrCode: 803, ErrMsg: ArgsMsg.Error()}
ErrStatus = ErrInfo{ErrCode: 804, ErrMsg: StatusMsg.Error()}
ErrCallback = ErrInfo{ErrCode: 809, ErrMsg: CallBackMsg.Error()}
)
var (
ParseTokenMsg = errors.New("parse token failed")
TokenExpiredMsg = errors.New("token is timed out, please log in again")
TokenInvalidMsg = errors.New("token has been invalidated")
TokenNotValidYetMsg = errors.New("token not active yet")
TokenMalformedMsg = errors.New("that's not even a token")
TokenUnknownMsg = errors.New("couldn't handle this token")
TokenUserKickedMsg = errors.New("user has been kicked")
AccessMsg = errors.New("no permission")
StatusMsg = errors.New("status is abnormal")
DBMsg = errors.New("db failed")
ArgsMsg = errors.New("args failed")
CallBackMsg = errors.New("callback failed")
ThirdPartyMsg = errors.New("third party error")
)
const (
NoError = 0
FormattingError = 10001
HasRegistered = 10002
NotRegistered = 10003
PasswordErr = 10004
GetIMTokenErr = 10005
RepeatSendCode = 10006
MailSendCodeErr = 10007
SmsSendCodeErr = 10008
CodeInvalidOrExpired = 10009
RegisterFailed = 10010
ResetPasswordFailed = 10011
DatabaseError = 10002
ServerError = 10004
HttpError = 10005
IoError = 10006
IntentionalError = 10007
)
func (e ErrInfo) Error() string {
return e.ErrMsg
}
func (e *ErrInfo) Code() int32 {
return e.ErrCode
}
+7
View File
@@ -0,0 +1,7 @@
package constant
const (
ShowNumber = 1000
StatisticsTimeInterval = 60
MaxNotificationNum = 500
)
@@ -0,0 +1,90 @@
package constant
// fixme 1<--->IOS 2<--->Android 3<--->Windows
//fixme 4<--->OSX 5<--->Web 6<--->MiniWeb 7<--->Linux
const (
//Platform ID
IOSPlatformID = 1
AndroidPlatformID = 2
WindowsPlatformID = 3
OSXPlatformID = 4
WebPlatformID = 5
MiniWebPlatformID = 6
LinuxPlatformID = 7
AndroidPadPlatformID = 8
IPadPlatformID = 9
AdminPlatformID = 10
//Platform string match to Platform ID
IOSPlatformStr = "IOS"
AndroidPlatformStr = "Android"
WindowsPlatformStr = "Windows"
OSXPlatformStr = "OSX"
WebPlatformStr = "Web"
MiniWebPlatformStr = "MiniWeb"
LinuxPlatformStr = "Linux"
AndroidPadPlatformStr = "APad"
IPadPlatformStr = "IPad"
AdminPlatformStr = "Admin"
//terminal types
TerminalPC = "PC"
TerminalMobile = "Mobile"
)
var PlatformID2Name = map[int]string{
IOSPlatformID: IOSPlatformStr,
AndroidPlatformID: AndroidPlatformStr,
WindowsPlatformID: WindowsPlatformStr,
OSXPlatformID: OSXPlatformStr,
WebPlatformID: WebPlatformStr,
MiniWebPlatformID: MiniWebPlatformStr,
LinuxPlatformID: LinuxPlatformStr,
AndroidPadPlatformID: AndroidPadPlatformStr,
IPadPlatformID: IPadPlatformStr,
AdminPlatformID: AdminPlatformStr,
}
var PlatformName2ID = map[string]int{
IOSPlatformStr: IOSPlatformID,
AndroidPlatformStr: AndroidPlatformID,
WindowsPlatformStr: WindowsPlatformID,
OSXPlatformStr: OSXPlatformID,
WebPlatformStr: WebPlatformID,
MiniWebPlatformStr: MiniWebPlatformID,
LinuxPlatformStr: LinuxPlatformID,
AndroidPadPlatformStr: AndroidPadPlatformID,
IPadPlatformStr: IPadPlatformID,
AdminPlatformStr: AdminPlatformID,
}
var PlatformName2class = map[string]string{
IOSPlatformStr: TerminalMobile,
AndroidPlatformStr: TerminalMobile,
MiniWebPlatformStr: WebPlatformStr,
WebPlatformStr: WebPlatformStr,
WindowsPlatformStr: TerminalPC,
OSXPlatformStr: TerminalPC,
LinuxPlatformStr: TerminalPC,
}
var PlatformID2class = map[int]string{
IOSPlatformID: TerminalMobile,
AndroidPlatformID: TerminalMobile,
MiniWebPlatformID: WebPlatformStr,
WebPlatformID: WebPlatformStr,
WindowsPlatformID: TerminalPC,
OSXPlatformID: TerminalPC,
LinuxPlatformID: TerminalPC,
}
func PlatformIDToName(num int) string {
return PlatformID2Name[num]
}
func PlatformNameToID(name string) int {
return PlatformName2ID[name]
}
func PlatformNameToClass(name string) string {
return PlatformName2class[name]
}
func PlatformIDToClass(num int) string {
return PlatformID2class[num]
}
@@ -1,66 +0,0 @@
package constant
// fixme 1<--->IOS 2<--->Android 3<--->Windows
//fixme 4<--->OSX 5<--->Web 6<--->MiniWeb 7<--->Linux
const (
//Platform ID
IOSPlatformID = 1
AndroidPlatformID = 2
WindowsPlatformID = 3
OSXPlatformID = 4
WebPlatformID = 5
MiniWebPlatformID = 6
LinuxPlatformID = 7
//Platform string match to Platform ID
IOSPlatformStr = "IOS"
AndroidPlatformStr = "Android"
WindowsPlatformStr = "Windows"
OSXPlatformStr = "OSX"
WebPlatformStr = "Web"
MiniWebPlatformStr = "MiniWeb"
LinuxPlatformStr = "Linux"
//terminal types
TerminalPC = "PC"
TerminalMobile = "Mobile"
)
var PlatformID2Name = map[int32]string{
IOSPlatformID: IOSPlatformStr,
AndroidPlatformID: AndroidPlatformStr,
WindowsPlatformID: WindowsPlatformStr,
OSXPlatformID: OSXPlatformStr,
WebPlatformID: WebPlatformStr,
MiniWebPlatformID: MiniWebPlatformStr,
LinuxPlatformID: LinuxPlatformStr,
}
var PlatformName2ID = map[string]int32{
IOSPlatformStr: IOSPlatformID,
AndroidPlatformStr: AndroidPlatformID,
WindowsPlatformStr: WindowsPlatformID,
OSXPlatformStr: OSXPlatformID,
WebPlatformStr: WebPlatformID,
MiniWebPlatformStr: MiniWebPlatformID,
LinuxPlatformStr: LinuxPlatformID,
}
var Platform2class = map[string]string{
IOSPlatformStr: TerminalMobile,
AndroidPlatformStr: TerminalMobile,
MiniWebPlatformStr: WebPlatformStr,
WebPlatformStr: WebPlatformStr,
WindowsPlatformStr: TerminalPC,
OSXPlatformStr: TerminalPC,
LinuxPlatformStr: TerminalPC,
}
func PlatformIDToName(num int32) string {
return PlatformID2Name[num]
}
func PlatformNameToID(name string) int32 {
return PlatformName2ID[name]
}
func PlatformNameToClass(name string) string {
return Platform2class[name]
}
+37
View File
@@ -0,0 +1,37 @@
package convert
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
sdk "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/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) {
var userIDs []string
for _, blackDB := range blackDBs {
userIDs = append(userIDs, blackDB.BlockUserID)
}
userInfos, err := f(ctx, userIDs)
if err != nil {
return nil, err
}
for _, blackDB := range blackDBs {
blackPb := &sdk.BlackInfo{
OwnerUserID: blackDB.OwnerUserID,
CreateTime: blackDB.CreateTime.Unix(),
AddSource: blackDB.AddSource,
Ex: blackDB.Ex,
OperatorUserID: blackDB.OperatorUserID,
BlackUserInfo: &sdkws.PublicUserInfo{
UserID: userInfos[blackDB.BlockUserID].UserID,
Nickname: userInfos[blackDB.BlockUserID].Nickname,
FaceURL: userInfos[blackDB.BlockUserID].FaceURL,
Ex: userInfos[blackDB.BlockUserID].Ex,
},
}
blackPbs = append(blackPbs, blackPb)
}
return blackPbs, nil
}
+45
View File
@@ -0,0 +1,45 @@
package convert
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/conversation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
)
func ConversationDB2Pb(conversationDB *relation.ConversationModel) *conversation.Conversation {
conversationPB := &conversation.Conversation{}
if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil {
return nil
}
return conversationPB
}
func ConversationsDB2Pb(conversationsDB []*relation.ConversationModel) (conversationsPB []*conversation.Conversation) {
for _, conversationDB := range conversationsDB {
conversationPB := &conversation.Conversation{}
if err := utils.CopyStructFields(conversationPB, conversationDB); err != nil {
continue
}
conversationsPB = append(conversationsPB, conversationPB)
}
return conversationsPB
}
func ConversationPb2DB(conversationPB *conversation.Conversation) *relation.ConversationModel {
conversationDB := &relation.ConversationModel{}
if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil {
return nil
}
return conversationDB
}
func ConversationsPb2DB(conversationsPB []*conversation.Conversation) (conversationsDB []*relation.ConversationModel) {
for _, conversationPB := range conversationsPB {
conversationDB := &relation.ConversationModel{}
if err := utils.CopyStructFields(conversationDB, conversationPB); err != nil {
continue
}
conversationsDB = append(conversationsDB, conversationDB)
}
return conversationsDB
}
+87
View File
@@ -0,0 +1,87 @@
package convert
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
)
func FriendPb2DB(friend *sdkws.FriendInfo) *relation.FriendModel {
dbFriend := &relation.FriendModel{}
utils.CopyStructFields(dbFriend, friend)
dbFriend.FriendUserID = friend.FriendUser.UserID
dbFriend.CreateTime = utils.UnixSecondToTime(friend.CreateTime)
return dbFriend
}
func FriendDB2Pb(ctx context.Context, friendDB *relation.FriendModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (*sdkws.FriendInfo, error) {
pbfriend := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}}
utils.CopyStructFields(pbfriend, friendDB)
users, err := getUsers(ctx, []string{friendDB.FriendUserID})
if err != nil {
return nil, err
}
pbfriend.FriendUser.UserID = users[friendDB.FriendUserID].UserID
pbfriend.FriendUser.Nickname = users[friendDB.FriendUserID].Nickname
pbfriend.FriendUser.FaceURL = users[friendDB.FriendUserID].FaceURL
pbfriend.FriendUser.Ex = users[friendDB.FriendUserID].Ex
pbfriend.CreateTime = friendDB.CreateTime.Unix()
return pbfriend, nil
}
func FriendsDB2Pb(ctx context.Context, friendsDB []*relation.FriendModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (friendsPb []*sdkws.FriendInfo, err error) {
var userID []string
for _, friendDB := range friendsDB {
userID = append(userID, friendDB.FriendUserID)
}
users, err := getUsers(ctx, userID)
if err != nil {
return nil, err
}
for _, friend := range friendsDB {
friendPb := &sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}}
utils.CopyStructFields(friendPb, friend)
friendPb.FriendUser.UserID = users[friend.FriendUserID].UserID
friendPb.FriendUser.Nickname = users[friend.FriendUserID].Nickname
friendPb.FriendUser.FaceURL = users[friend.FriendUserID].FaceURL
friendPb.FriendUser.Ex = users[friend.FriendUserID].Ex
friendPb.CreateTime = friend.CreateTime.Unix()
friendsPb = append(friendsPb, friendPb)
}
return friendsPb, nil
}
func FriendRequestDB2Pb(ctx context.Context, friendRequests []*relation.FriendRequestModel, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) ([]*sdkws.FriendRequest, error) {
userIDMap := make(map[string]struct{})
for _, friendRequest := range friendRequests {
userIDMap[friendRequest.ToUserID] = struct{}{}
userIDMap[friendRequest.FromUserID] = struct{}{}
}
users, err := getUsers(ctx, utils.Keys(userIDMap))
if err != nil {
return nil, err
}
res := make([]*sdkws.FriendRequest, 0, len(friendRequests))
for _, friendRequest := range friendRequests {
toUser := users[friendRequest.ToUserID]
fromUser := users[friendRequest.FromUserID]
res = append(res, &sdkws.FriendRequest{
FromUserID: friendRequest.FromUserID,
FromNickname: fromUser.Nickname,
FromFaceURL: fromUser.FaceURL,
ToUserID: friendRequest.ToUserID,
ToNickname: toUser.Nickname,
ToFaceURL: toUser.FaceURL,
HandleResult: friendRequest.HandleResult,
ReqMsg: friendRequest.ReqMsg,
CreateTime: friendRequest.CreateTime.UnixMilli(),
HandlerUserID: friendRequest.HandlerUserID,
HandleMsg: friendRequest.HandleMsg,
HandleTime: friendRequest.HandleTime.UnixMilli(),
Ex: friendRequest.Ex,
})
}
return res, nil
}
+120
View File
@@ -0,0 +1,120 @@
package convert
import (
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
pbGroup "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/group"
sdkws "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
func Db2PbGroupInfo(m *relation.GroupModel, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
return &sdkws.GroupInfo{
GroupID: m.GroupID,
GroupName: m.GroupName,
Notification: m.Notification,
Introduction: m.Introduction,
FaceURL: m.FaceURL,
OwnerUserID: ownerUserID,
CreateTime: m.CreateTime.UnixMilli(),
MemberCount: memberCount,
Ex: m.Ex,
Status: m.Status,
CreatorUserID: m.CreatorUserID,
GroupType: m.GroupType,
NeedVerification: m.NeedVerification,
LookMemberInfo: m.LookMemberInfo,
ApplyMemberFriend: m.ApplyMemberFriend,
NotificationUpdateTime: m.NotificationUpdateTime.UnixMilli(),
NotificationUserID: m.NotificationUserID,
}
}
func Pb2DbGroupRequest(req *pbGroup.GroupApplicationResponseReq, handleUserID string) *relation.GroupRequestModel {
return &relation.GroupRequestModel{
UserID: req.FromUserID,
GroupID: req.GroupID,
HandleResult: req.HandleResult,
HandledMsg: req.HandledMsg,
HandleUserID: handleUserID,
HandledTime: time.Now(),
}
}
func Db2PbCMSGroup(m *relation.GroupModel, ownerUserID string, ownerUserName string, memberCount uint32) *pbGroup.CMSGroup {
return &pbGroup.CMSGroup{
GroupInfo: Db2PbGroupInfo(m, ownerUserID, memberCount),
GroupOwnerUserID: ownerUserID,
GroupOwnerUserName: ownerUserName,
}
}
func Db2PbGroupMember(m *relation.GroupMemberModel) *sdkws.GroupMemberFullInfo {
return &sdkws.GroupMemberFullInfo{
GroupID: m.GroupID,
UserID: m.UserID,
RoleLevel: m.RoleLevel,
JoinTime: m.JoinTime.UnixMilli(),
Nickname: m.Nickname,
FaceURL: m.FaceURL,
//AppMangerLevel: m.AppMangerLevel,
JoinSource: m.JoinSource,
OperatorUserID: m.OperatorUserID,
Ex: m.Ex,
MuteEndTime: m.MuteEndTime.UnixMilli(),
InviterUserID: m.InviterUserID,
}
}
func Db2PbGroupRequest(m *relation.GroupRequestModel, user *sdkws.PublicUserInfo, group *sdkws.GroupInfo) *sdkws.GroupRequest {
return &sdkws.GroupRequest{
UserInfo: user,
GroupInfo: group,
HandleResult: m.HandleResult,
ReqMsg: m.ReqMsg,
HandleMsg: m.HandledMsg,
ReqTime: m.ReqTime.UnixMilli(),
HandleUserID: m.HandleUserID,
HandleTime: m.HandledTime.UnixMilli(),
Ex: m.Ex,
JoinSource: m.JoinSource,
InviterUserID: m.InviterUserID,
}
}
func Db2PbGroupAbstractInfo(groupID string, groupMemberNumber uint32, groupMemberListHash uint64) *pbGroup.GroupAbstractInfo {
return &pbGroup.GroupAbstractInfo{
GroupID: groupID,
GroupMemberNumber: groupMemberNumber,
GroupMemberListHash: groupMemberListHash,
}
}
func Pb2DBGroupInfo(m *sdkws.GroupInfo) *relation.GroupModel {
return &relation.GroupModel{
GroupID: m.GroupID,
GroupName: m.GroupName,
Notification: m.Notification,
Introduction: m.Introduction,
FaceURL: m.FaceURL,
CreateTime: time.Now(),
Ex: m.Ex,
Status: m.Status,
CreatorUserID: m.CreatorUserID,
GroupType: m.GroupType,
NeedVerification: m.NeedVerification,
LookMemberInfo: m.LookMemberInfo,
ApplyMemberFriend: m.ApplyMemberFriend,
NotificationUpdateTime: time.UnixMilli(m.NotificationUpdateTime),
NotificationUserID: m.NotificationUserID,
}
}
func Pb2DbGroupMember(m *sdkws.UserInfo) *relation.GroupMemberModel {
return &relation.GroupMemberModel{
UserID: m.UserID,
Nickname: m.Nickname,
FaceURL: m.FaceURL,
Ex: m.Ex,
}
}
+81
View File
@@ -0,0 +1,81 @@
package convert
import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
func MsgPb2DB(msg *sdkws.MsgData) *unrelation.MsgDataModel {
if msg == nil {
return nil
}
var msgDataModel unrelation.MsgDataModel
msgDataModel.SendID = msg.SendID
msgDataModel.RecvID = msg.RecvID
msgDataModel.GroupID = msg.GroupID
msgDataModel.ClientMsgID = msg.ClientMsgID
msgDataModel.ServerMsgID = msg.ServerMsgID
msgDataModel.SenderPlatformID = msg.SenderPlatformID
msgDataModel.SenderNickname = msg.SenderNickname
msgDataModel.SenderFaceURL = msg.SenderFaceURL
msgDataModel.SessionType = msg.SessionType
msgDataModel.MsgFrom = msg.MsgFrom
msgDataModel.ContentType = msg.ContentType
msgDataModel.Content = string(msg.Content)
msgDataModel.Seq = msg.Seq
msgDataModel.SendTime = msg.SendTime
msgDataModel.CreateTime = msg.CreateTime
msgDataModel.Status = msg.Status
msgDataModel.Options = msg.Options
if msg.OfflinePushInfo != nil {
msgDataModel.OfflinePush = &unrelation.OfflinePushModel{
Title: msg.OfflinePushInfo.Title,
Desc: msg.OfflinePushInfo.Desc,
Ex: msg.OfflinePushInfo.Ex,
IOSPushSound: msg.OfflinePushInfo.IOSPushSound,
IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount,
}
}
msgDataModel.AtUserIDList = msg.AtUserIDList
msgDataModel.AttachedInfo = msg.AttachedInfo
msgDataModel.Ex = msg.Ex
return &msgDataModel
}
func MsgDB2Pb(msgModel *unrelation.MsgDataModel) *sdkws.MsgData {
if msgModel == nil {
return nil
}
var msg sdkws.MsgData
msg.SendID = msgModel.SendID
msg.RecvID = msgModel.RecvID
msg.GroupID = msgModel.GroupID
msg.ClientMsgID = msgModel.ClientMsgID
msg.ServerMsgID = msgModel.ServerMsgID
msg.SenderPlatformID = msgModel.SenderPlatformID
msg.SenderNickname = msgModel.SenderNickname
msg.SenderFaceURL = msgModel.SenderFaceURL
msg.SessionType = msgModel.SessionType
msg.MsgFrom = msgModel.MsgFrom
msg.ContentType = msgModel.ContentType
msg.Content = []byte(msgModel.Content)
msg.Seq = msgModel.Seq
msg.SendTime = msgModel.SendTime
msg.CreateTime = msgModel.CreateTime
msg.Status = msgModel.Status
msg.Options = msgModel.Options
if msgModel.OfflinePush != nil {
msg.OfflinePushInfo = &sdkws.OfflinePushInfo{
Title: msgModel.OfflinePush.Title,
Desc: msgModel.OfflinePush.Desc,
Ex: msgModel.OfflinePush.Ex,
IOSPushSound: msgModel.OfflinePush.IOSPushSound,
IOSBadgeCount: msgModel.OfflinePush.IOSBadgeCount,
}
}
msg.AtUserIDList = msgModel.AtUserIDList
msg.AttachedInfo = msgModel.AttachedInfo
msg.Ex = msgModel.Ex
return &msg
}
+35
View File
@@ -0,0 +1,35 @@
package convert
import (
"time"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
)
func UsersDB2Pb(users []*relationTb.UserModel) (result []*sdkws.UserInfo) {
for _, user := range users {
var userPb sdkws.UserInfo
userPb.UserID = user.UserID
userPb.Nickname = user.Nickname
userPb.FaceURL = user.FaceURL
userPb.Ex = user.Ex
userPb.CreateTime = user.CreateTime.UnixMilli()
userPb.AppMangerLevel = user.AppMangerLevel
userPb.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt
result = append(result, &userPb)
}
return result
}
func UserPb2DB(user *sdkws.UserInfo) *relationTb.UserModel {
var userDB relationTb.UserModel
userDB.UserID = user.UserID
userDB.Nickname = user.Nickname
userDB.FaceURL = user.FaceURL
userDB.Ex = user.Ex
userDB.CreateTime = time.UnixMilli(user.CreateTime)
userDB.AppMangerLevel = user.AppMangerLevel
userDB.GlobalRecvMsgOpt = user.GlobalRecvMsgOpt
return &userDB
}
-100
View File
@@ -1,100 +0,0 @@
package db
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/log"
pbMsg "Open_IM/pkg/proto/chat"
server_api_params "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"errors"
"github.com/garyburd/redigo/redis"
"github.com/golang/protobuf/proto"
"go.mongodb.org/mongo-driver/bson"
)
func (d *DataBases) BatchInsertChat(userID string, msgList []*pbMsg.MsgDataToMQ, operationID string) error {
newTime := getCurrentTimestampByMill()
if len(msgList) > GetSingleGocMsgNum() {
return errors.New("too large")
}
isInit := false
currentMaxSeq, err := d.GetUserMaxSeq(userID)
if err == nil {
} else if err == redis.ErrNil {
isInit = true
currentMaxSeq = 0
} else {
return utils.Wrap(err, "")
}
var remain uint64
if currentMaxSeq < uint64(GetSingleGocMsgNum()) {
remain = uint64(GetSingleGocMsgNum()-1) - (currentMaxSeq % uint64(GetSingleGocMsgNum()))
} else {
remain = uint64(GetSingleGocMsgNum()) - ((currentMaxSeq - 4999) % uint64(GetSingleGocMsgNum()))
}
insertCounter := uint64(0)
msgListToMongo := make([]MsgInfo, 0)
msgListToMongoNext := make([]MsgInfo, 0)
seqUid := ""
seqUidNext := ""
log.Debug(operationID, "remain ", remain, "insertCounter ", insertCounter, "currentMaxSeq ", currentMaxSeq, userID)
for _, m := range msgList {
log.Debug(operationID, "msg node ", m.String(), m.MsgData.ClientMsgID)
currentMaxSeq++
sMsg := MsgInfo{}
sMsg.SendTime = m.MsgData.SendTime
m.MsgData.Seq = uint32(currentMaxSeq)
if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil {
return utils.Wrap(err, "")
}
if isInit {
msgListToMongoNext = append(msgListToMongoNext, sMsg)
seqUidNext = getSeqUid(userID, uint32(currentMaxSeq))
log.Debug(operationID, "msgListToMongoNext ", seqUidNext, m.MsgData.Seq, m.MsgData.ClientMsgID, insertCounter, remain)
continue
}
if insertCounter < remain {
msgListToMongo = append(msgListToMongo, sMsg)
insertCounter++
seqUid = getSeqUid(userID, uint32(currentMaxSeq))
log.Debug(operationID, "msgListToMongo ", seqUid, m.MsgData.Seq, m.MsgData.ClientMsgID, insertCounter, remain)
} else {
msgListToMongoNext = append(msgListToMongoNext, sMsg)
seqUidNext = getSeqUid(userID, uint32(currentMaxSeq))
log.Debug(operationID, "msgListToMongoNext ", seqUidNext, m.MsgData.Seq, m.MsgData.ClientMsgID, insertCounter, remain)
}
}
// ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
ctx := context.Background()
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
if seqUid != "" {
filter := bson.M{"uid": seqUid}
log.NewDebug(operationID, "filter ", seqUid, "list ", msgListToMongo)
err := c.FindOneAndUpdate(ctx, filter, bson.M{"$push": bson.M{"msg": bson.M{"$each": msgListToMongo}}}).Err()
if err != nil {
log.Error(operationID, "FindOneAndUpdate failed ", err.Error(), filter)
return utils.Wrap(err, "")
}
}
if seqUidNext != "" {
filter := bson.M{"uid": seqUidNext}
sChat := UserChat{}
sChat.UID = seqUidNext
sChat.Msg = msgListToMongoNext
log.NewDebug(operationID, "filter ", seqUidNext, "list ", msgListToMongoNext)
if _, err = c.InsertOne(ctx, &sChat); err != nil {
log.NewError(operationID, "InsertOne failed", filter, err.Error(), sChat)
return utils.Wrap(err, "")
}
}
log.NewWarn(operationID, "batch mgo cost time ", getCurrentTimestampByMill()-newTime, userID, len(msgList))
return utils.Wrap(d.SetUserMaxSeq(userID, uint64(currentMaxSeq)), "")
}
func setMessageToCache(msgList []*server_api_params.MsgData, uid string) (err error) {
return err
}
+67
View File
@@ -0,0 +1,67 @@
package cache
import (
"context"
"time"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
)
const (
blackIDsKey = "BLACK_IDS:"
blackExpireTime = time.Second * 60 * 60 * 12
)
// args fn will exec when no data in msgCache
type BlackCache interface {
//get blackIDs from msgCache
metaCache
NewCache() BlackCache
GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error)
//del user's blackIDs msgCache, exec when a user's black list changed
DelBlackIDs(ctx context.Context, userID string) BlackCache
}
type BlackCacheRedis struct {
metaCache
expireTime time.Duration
rcClient *rockscache.Client
blackDB relationTb.BlackModelInterface
}
func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationTb.BlackModelInterface, options rockscache.Options) BlackCache {
rcClient := rockscache.NewClient(rdb, options)
return &BlackCacheRedis{
expireTime: blackExpireTime,
rcClient: rcClient,
metaCache: NewMetaCacheRedis(rcClient),
blackDB: blackDB,
}
}
func (b *BlackCacheRedis) NewCache() BlackCache {
return &BlackCacheRedis{
expireTime: b.expireTime,
rcClient: b.rcClient,
blackDB: b.blackDB,
metaCache: NewMetaCacheRedis(b.rcClient, b.metaCache.GetPreDelKeys()...),
}
}
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
return blackIDsKey + ownerUserID
}
func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) {
return getCache(ctx, b.rcClient, b.getBlackIDsKey(userID), b.expireTime, func(ctx context.Context) ([]string, error) {
return b.blackDB.FindBlackUserIDs(ctx, userID)
})
}
func (b *BlackCacheRedis) DelBlackIDs(ctx context.Context, userID string) BlackCache {
cache := b.NewCache()
cache.AddKeys(b.getBlackIDsKey(userID))
return cache
}
+293
View File
@@ -0,0 +1,293 @@
package cache
import (
"context"
"errors"
"math/big"
"strings"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/relation"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
"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:"
conversationExpireTime = time.Second * 60 * 60 * 12
)
// arg fn will exec when no data in msgCache
type ConversationCache interface {
metaCache
NewCache() ConversationCache
// get user's conversationIDs from msgCache
GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error)
DelConversationIDs(userIDs ...string) ConversationCache
GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error)
DelUserConversationIDsHash(ownerUserIDs ...string) ConversationCache
// get one conversation from msgCache
GetConversation(ctx context.Context, ownerUserID, conversationID string) (*relationTb.ConversationModel, error)
DelConvsersations(ownerUserID string, conversationIDs ...string) ConversationCache
DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache
// get one conversation from msgCache
GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationTb.ConversationModel, error)
// get one user's all conversations from msgCache
GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*relationTb.ConversationModel, error)
// get user conversation recv msg from msgCache
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)
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)
DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache
GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
DelUserAllHasReadSeqs(ownerUserID string, conversationIDs ...string) ConversationCache
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationTb.ConversationModel, error)
DelConversationByConversationID(conversationIDs ...string) ConversationCache
}
func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationTb.ConversationModelInterface) ConversationCache {
rcClient := rockscache.NewClient(rdb, opts)
return &ConversationRedisCache{rcClient: rcClient, metaCache: NewMetaCacheRedis(rcClient), conversationDB: db, expireTime: conversationExpireTime}
}
type ConversationRedisCache struct {
metaCache
rcClient *rockscache.Client
conversationDB relationTb.ConversationModelInterface
expireTime time.Duration
}
func NewNewConversationRedis(rdb redis.UniversalClient, conversationDB *relation.ConversationGorm, options rockscache.Options) ConversationCache {
rcClient := rockscache.NewClient(rdb, options)
return &ConversationRedisCache{rcClient: rcClient, metaCache: NewMetaCacheRedis(rcClient), conversationDB: conversationDB, expireTime: conversationExpireTime}
}
func (c *ConversationRedisCache) NewCache() ConversationCache {
return &ConversationRedisCache{rcClient: c.rcClient, metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...), conversationDB: c.conversationDB, expireTime: c.expireTime}
}
func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string {
return conversationKey + ownerUserID + ":" + conversationID
}
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
return conversationIDsKey + ownerUserID
}
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
return superGroupRecvMsgNotNotifyUserIDsKey + groupID
}
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
return recvMsgOptKey + ownerUserID + ":" + conversationID
}
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID
}
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
return conversationHasReadSeqKey + ownerUserID + ":" + conversationID
}
func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
return getCache(ctx, c.rcClient, c.getConversationIDsKey(ownerUserID), c.expireTime, func(ctx context.Context) ([]string, error) {
return c.conversationDB.FindUserIDAllConversationID(ctx, ownerUserID)
})
}
func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) ConversationCache {
var keys []string
for _, userID := range userIDs {
keys = append(keys, c.getConversationIDsKey(userID))
}
cache := c.NewCache()
cache.AddKeys(keys...)
return cache
}
func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string {
return conversationIDsHashKey + ownerUserID
}
func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) {
return getCache(ctx, c.rcClient, c.getUserConversationIDsHashKey(ownerUserID), c.expireTime, func(ctx context.Context) (uint64, error) {
conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
if err != nil {
return 0, err
}
utils.Sort(conversationIDs, true)
bi := big.NewInt(0)
bi.SetString(utils.Md5(strings.Join(conversationIDs, ";"))[0:8], 16)
return bi.Uint64(), nil
})
}
func (c *ConversationRedisCache) DelUserConversationIDsHash(ownerUserIDs ...string) ConversationCache {
var keys []string
for _, ownerUserID := range ownerUserIDs {
keys = append(keys, c.getUserConversationIDsHashKey(ownerUserID))
}
cache := c.NewCache()
cache.AddKeys(keys...)
return cache
}
func (c *ConversationRedisCache) GetConversation(ctx context.Context, ownerUserID, conversationID string) (*relationTb.ConversationModel, error) {
return getCache(ctx, c.rcClient, c.getConversationKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (*relationTb.ConversationModel, error) {
return c.conversationDB.Take(ctx, ownerUserID, conversationID)
})
}
func (c *ConversationRedisCache) DelConvsersations(ownerUserID string, convsersationIDs ...string) ConversationCache {
var keys []string
for _, conversationID := range convsersationIDs {
keys = append(keys, c.getConversationKey(ownerUserID, conversationID))
}
cache := c.NewCache()
cache.AddKeys(keys...)
return cache
}
func (c *ConversationRedisCache) getConversationIndex(convsation *relationTb.ConversationModel, keys []string) (int, error) {
key := c.getConversationKey(convsation.OwnerUserID, convsation.ConversationID)
for _i, _key := range keys {
if _key == key {
return _i, nil
}
}
return 0, errors.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 {
keys = append(keys, c.getConversationKey(ownerUserID, conversarionID))
}
return batchGetCache(ctx, c.rcClient, keys, c.expireTime, c.getConversationIndex, func(ctx context.Context) ([]*relationTb.ConversationModel, error) {
return c.conversationDB.Find(ctx, ownerUserID, conversationIDs)
})
}
func (c *ConversationRedisCache) GetUserAllConversations(ctx context.Context, ownerUserID string) ([]*relationTb.ConversationModel, error) {
conversationIDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
if err != nil {
return nil, err
}
var keys []string
for _, conversarionID := range conversationIDs {
keys = append(keys, c.getConversationKey(ownerUserID, conversarionID))
}
return batchGetCache(ctx, c.rcClient, keys, c.expireTime, c.getConversationIndex, func(ctx context.Context) ([]*relationTb.ConversationModel, error) {
return c.conversationDB.FindUserIDAllConversations(ctx, ownerUserID)
})
}
func (c *ConversationRedisCache) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) {
return getCache(ctx, c.rcClient, c.getRecvMsgOptKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (opt int, err error) {
return c.conversationDB.GetUserRecvMsgOpt(ctx, ownerUserID, conversationID)
})
}
func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) (userIDs []string, err error) {
return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsKey(groupID), c.expireTime, func(ctx context.Context) (userIDs []string, err error) {
return c.conversationDB.FindSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
})
}
func (c *ConversationRedisCache) DelUsersConversation(conversationID string, ownerUserIDs ...string) ConversationCache {
var keys []string
for _, ownerUserID := range ownerUserIDs {
keys = append(keys, c.getConversationKey(ownerUserID, conversationID))
}
cache := c.NewCache()
cache.AddKeys(keys...)
return cache
}
func (c *ConversationRedisCache) DelUserRecvMsgOpt(ownerUserID, conversationID string) ConversationCache {
cache := c.NewCache()
cache.AddKeys(c.getRecvMsgOptKey(ownerUserID, conversationID))
return cache
}
func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDs(groupID string) ConversationCache {
cache := c.NewCache()
cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsKey(groupID))
return cache
}
func (c *ConversationRedisCache) GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint64, err error) {
return getCache(ctx, c.rcClient, c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID), c.expireTime, func(ctx context.Context) (hash uint64, err error) {
userIDs, err := c.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
if err != nil {
return 0, err
}
utils.Sort(userIDs, true)
bi := big.NewInt(0)
bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16)
return bi.Uint64(), nil
})
}
func (c *ConversationRedisCache) DelSuperGroupRecvMsgNotNotifyUserIDsHash(groupID string) ConversationCache {
cache := c.NewCache()
cache.AddKeys(c.getSuperGroupRecvNotNotifyUserIDsHashKey(groupID))
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 {
cache.AddKeys(c.getConversationHasReadSeqKey(ownerUserID, conversationID))
}
return cache
}
func (c *ConversationRedisCache) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationTb.ConversationModel, error) {
panic("implement me")
}
func (c *ConversationRedisCache) DelConversationByConversationID(conversationIDs ...string) ConversationCache {
panic("implement me")
}
+64
View File
@@ -0,0 +1,64 @@
package cache
import (
"context"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
)
const (
extendMsgSetCache = "EXTEND_MSG_SET_CACHE:"
extendMsgCache = "EXTEND_MSG_CACHE:"
)
type ExtendMsgSetCache interface {
metaCache
NewCache() ExtendMsgSetCache
GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, firstModifyTime int64) (extendMsg *unrelation.ExtendMsgModel, err error)
DelExtendMsg(clientMsgID string) ExtendMsgSetCache
}
type ExtendMsgSetCacheRedis struct {
metaCache
expireTime time.Duration
rcClient *rockscache.Client
extendMsgSetDB unrelation.ExtendMsgSetModelInterface
}
func NewExtendMsgSetCacheRedis(rdb redis.UniversalClient, extendMsgSetDB unrelation.ExtendMsgSetModelInterface, options rockscache.Options) ExtendMsgSetCache {
rcClient := rockscache.NewClient(rdb, options)
return &ExtendMsgSetCacheRedis{
metaCache: NewMetaCacheRedis(rcClient),
expireTime: time.Second * 30 * 60,
extendMsgSetDB: extendMsgSetDB,
rcClient: rcClient,
}
}
func (e *ExtendMsgSetCacheRedis) NewCache() ExtendMsgSetCache {
return &ExtendMsgSetCacheRedis{
metaCache: NewMetaCacheRedis(e.rcClient, e.metaCache.GetPreDelKeys()...),
expireTime: e.expireTime,
extendMsgSetDB: e.extendMsgSetDB,
rcClient: e.rcClient,
}
}
func (e *ExtendMsgSetCacheRedis) getKey(clientMsgID string) string {
return extendMsgCache + clientMsgID
}
func (e *ExtendMsgSetCacheRedis) GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, firstModifyTime int64) (extendMsg *unrelation.ExtendMsgModel, err error) {
return getCache(ctx, e.rcClient, e.getKey(clientMsgID), e.expireTime, func(ctx context.Context) (*unrelation.ExtendMsgModel, error) {
return e.extendMsgSetDB.TakeExtendMsg(ctx, conversationID, sessionType, clientMsgID, firstModifyTime)
})
}
func (e *ExtendMsgSetCacheRedis) DelExtendMsg(clientMsgID string) ExtendMsgSetCache {
new := e.NewCache()
new.AddKeys(e.getKey(clientMsgID))
return new
}
+116
View File
@@ -0,0 +1,116 @@
package cache
import (
"context"
"time"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
)
const (
friendExpireTime = time.Second * 60 * 60 * 12
friendIDsKey = "FRIEND_IDS:"
TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
friendKey = "FRIEND_INFO:"
)
// args fn will exec when no data in msgCache
type FriendCache interface {
metaCache
NewCache() FriendCache
GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error)
// call when friendID List changed
DelFriendIDs(ownerUserID ...string) FriendCache
// get single friendInfo from msgCache
GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationTb.FriendModel, err error)
// del friend when friend info changed
DelFriend(ownerUserID, friendUserID string) FriendCache
}
type FriendCacheRedis struct {
metaCache
friendDB relationTb.FriendModelInterface
expireTime time.Duration
rcClient *rockscache.Client
}
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationTb.FriendModelInterface, options rockscache.Options) FriendCache {
rcClient := rockscache.NewClient(rdb, options)
return &FriendCacheRedis{
metaCache: NewMetaCacheRedis(rcClient),
friendDB: friendDB,
expireTime: friendExpireTime,
rcClient: rcClient,
}
}
func (c *FriendCacheRedis) NewCache() FriendCache {
return &FriendCacheRedis{rcClient: c.rcClient, metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...), friendDB: c.friendDB, expireTime: c.expireTime}
}
func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string {
return friendIDsKey + ownerUserID
}
func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string {
return TwoWayFriendsIDsKey + ownerUserID
}
func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string {
return friendKey + ownerUserID + "-" + friendUserID
}
func (f *FriendCacheRedis) GetFriendIDs(ctx context.Context, ownerUserID string) (friendIDs []string, err error) {
return getCache(ctx, f.rcClient, f.getFriendIDsKey(ownerUserID), f.expireTime, func(ctx context.Context) ([]string, error) {
return f.friendDB.FindFriendUserIDs(ctx, ownerUserID)
})
}
func (f *FriendCacheRedis) DelFriendIDs(ownerUserID ...string) FriendCache {
new := f.NewCache()
var keys []string
for _, userID := range ownerUserID {
keys = append(keys, f.getFriendIDsKey(userID))
}
new.AddKeys(keys...)
return new
}
// todo
func (f *FriendCacheRedis) GetTwoWayFriendIDs(ctx context.Context, ownerUserID string) (twoWayFriendIDs []string, err error) {
friendIDs, err := f.GetFriendIDs(ctx, ownerUserID)
if err != nil {
return nil, err
}
for _, friendID := range friendIDs {
friendFriendID, err := f.GetFriendIDs(ctx, friendID)
if err != nil {
return nil, err
}
if utils.IsContain(ownerUserID, friendFriendID) {
twoWayFriendIDs = append(twoWayFriendIDs, ownerUserID)
}
}
return twoWayFriendIDs, nil
}
func (f *FriendCacheRedis) DelTwoWayFriendIDs(ctx context.Context, ownerUserID string) FriendCache {
new := f.NewCache()
new.AddKeys(f.getTwoWayFriendsIDsKey(ownerUserID))
return new
}
func (f *FriendCacheRedis) GetFriend(ctx context.Context, ownerUserID, friendUserID string) (friend *relationTb.FriendModel, err error) {
return getCache(ctx, f.rcClient, f.getFriendKey(ownerUserID, friendUserID), f.expireTime, func(ctx context.Context) (*relationTb.FriendModel, error) {
return f.friendDB.Take(ctx, ownerUserID, friendUserID)
})
}
func (f *FriendCacheRedis) DelFriend(ownerUserID, friendUserID string) FriendCache {
new := f.NewCache()
new.AddKeys(f.getFriendKey(ownerUserID, friendUserID))
return new
}
+365
View File
@@ -0,0 +1,365 @@
package cache
import (
"context"
"math/big"
"strings"
"time"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
unrelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
)
const (
groupExpireTime = time.Second * 60 * 60 * 12
groupInfoKey = "GROUP_INFO:"
groupMemberIDsKey = "GROUP_MEMBER_IDS:"
groupMembersHashKey = "GROUP_MEMBERS_HASH:"
groupMemberInfoKey = "GROUP_MEMBER_INFO:"
joinedSuperGroupsKey = "JOIN_SUPER_GROUPS:"
SuperGroupMemberIDsKey = "SUPER_GROUP_MEMBER_IDS:"
joinedGroupsKey = "JOIN_GROUPS_KEY:"
groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
)
type GroupCache interface {
metaCache
NewCache() GroupCache
GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error)
GetGroupInfo(ctx context.Context, groupID string) (group *relationTb.GroupModel, err error)
DelGroupsInfo(groupIDs ...string) GroupCache
GetJoinedSuperGroupIDs(ctx context.Context, userID string) (joinedSuperGroupIDs []string, err error)
DelJoinedSuperGroupIDs(userIDs ...string) GroupCache
GetSuperGroupMemberIDs(ctx context.Context, groupIDs ...string) (models []*unrelationTb.SuperGroupModel, err error)
DelSuperGroupMemberIDs(groupIDs ...string) GroupCache
GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error)
GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationTb.GroupSimpleUserID, error)
DelGroupMembersHash(groupID string) GroupCache
GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error)
GetGroupsMemberIDs(ctx context.Context, groupIDs []string) (groupMemberIDs map[string][]string, err error)
DelGroupMemberIDs(groupID string) GroupCache
GetJoinedGroupIDs(ctx context.Context, userID string) (joinedGroupIDs []string, err error)
DelJoinedGroupID(userID ...string) GroupCache
GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *relationTb.GroupMemberModel, err error)
GetGroupMembersInfo(ctx context.Context, groupID string, userID []string) (groupMembers []*relationTb.GroupMemberModel, err error)
GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*relationTb.GroupMemberModel, err error)
GetGroupMembersPage(ctx context.Context, groupID string, userID []string, showNumber, pageNumber int32) (total uint32, groupMembers []*relationTb.GroupMemberModel, err error)
DelGroupMembersInfo(groupID string, userID ...string) GroupCache
GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error)
DelGroupsMemberNum(groupID ...string) GroupCache
}
type GroupCacheRedis struct {
metaCache
groupDB relationTb.GroupModelInterface
groupMemberDB relationTb.GroupMemberModelInterface
groupRequestDB relationTb.GroupRequestModelInterface
mongoDB unrelationTb.SuperGroupModelInterface
expireTime time.Duration
rcClient *rockscache.Client
}
func NewGroupCacheRedis(rdb redis.UniversalClient, groupDB relationTb.GroupModelInterface, groupMemberDB relationTb.GroupMemberModelInterface, groupRequestDB relationTb.GroupRequestModelInterface, mongoClient unrelationTb.SuperGroupModelInterface, opts rockscache.Options) GroupCache {
rcClient := rockscache.NewClient(rdb, opts)
return &GroupCacheRedis{rcClient: rcClient, expireTime: groupExpireTime,
groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB,
mongoDB: mongoClient, metaCache: NewMetaCacheRedis(rcClient),
}
}
func (g *GroupCacheRedis) NewCache() GroupCache {
return &GroupCacheRedis{rcClient: g.rcClient, expireTime: g.expireTime, groupDB: g.groupDB, groupMemberDB: g.groupMemberDB, groupRequestDB: g.groupRequestDB, mongoDB: g.mongoDB, metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...)}
}
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
return groupInfoKey + groupID
}
func (g *GroupCacheRedis) getJoinedSuperGroupsIDKey(userID string) string {
return joinedSuperGroupsKey + userID
}
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
return joinedGroupsKey + userID
}
func (g *GroupCacheRedis) getSuperGroupMemberIDsKey(groupID string) string {
return SuperGroupMemberIDsKey + groupID
}
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
return groupMembersHashKey + groupID
}
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
return groupMemberIDsKey + groupID
}
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
return groupMemberInfoKey + groupID + "-" + userID
}
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
return groupMemberNumKey + groupID
}
func (g *GroupCacheRedis) GetGroupIndex(group *relationTb.GroupModel, keys []string) (int, error) {
key := g.getGroupInfoKey(group.GroupID)
for i, _key := range keys {
if _key == key {
return i, nil
}
}
return 0, errIndex
}
func (g *GroupCacheRedis) GetGroupMemberIndex(groupMember *relationTb.GroupMemberModel, keys []string) (int, error) {
key := g.getGroupMemberInfoKey(groupMember.GroupID, groupMember.UserID)
for i, _key := range keys {
if _key == key {
return i, nil
}
}
return 0, errIndex
}
// / groupInfo
func (g *GroupCacheRedis) GetGroupsInfo(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error) {
var keys []string
for _, group := range groupIDs {
keys = append(keys, g.getGroupInfoKey(group))
}
return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupIndex, func(ctx context.Context) ([]*relationTb.GroupModel, error) {
return g.groupDB.Find(ctx, groupIDs)
})
}
func (g *GroupCacheRedis) GetGroupInfo(ctx context.Context, groupID string) (group *relationTb.GroupModel, err error) {
return getCache(ctx, g.rcClient, g.getGroupInfoKey(groupID), g.expireTime, func(ctx context.Context) (*relationTb.GroupModel, error) {
return g.groupDB.Take(ctx, groupID)
})
}
func (g *GroupCacheRedis) DelGroupsInfo(groupIDs ...string) GroupCache {
new := g.NewCache()
var keys []string
for _, groupID := range groupIDs {
keys = append(keys, g.getGroupInfoKey(groupID))
}
new.AddKeys(keys...)
return new
}
func (g *GroupCacheRedis) GetJoinedSuperGroupIDs(ctx context.Context, userID string) (joinedSuperGroupIDs []string, err error) {
return getCache(ctx, g.rcClient, g.getJoinedSuperGroupsIDKey(userID), g.expireTime, func(ctx context.Context) ([]string, error) {
userGroup, err := g.mongoDB.GetSuperGroupByUserID(ctx, userID)
if err != nil {
return nil, err
}
return userGroup.GroupIDs, nil
})
}
func (g *GroupCacheRedis) GetSuperGroupMemberIDs(ctx context.Context, groupIDs ...string) (models []*unrelationTb.SuperGroupModel, err error) {
var keys []string
for _, group := range groupIDs {
keys = append(keys, g.getSuperGroupMemberIDsKey(group))
}
return batchGetCache(ctx, g.rcClient, keys, g.expireTime, func(model *unrelationTb.SuperGroupModel, keys []string) (int, error) {
for i, key := range keys {
if g.getSuperGroupMemberIDsKey(model.GroupID) == key {
return i, nil
}
}
return 0, errIndex
}, func(ctx context.Context) ([]*unrelationTb.SuperGroupModel, error) {
return g.mongoDB.FindSuperGroup(ctx, groupIDs)
})
}
// userJoinSuperGroup
func (g *GroupCacheRedis) DelJoinedSuperGroupIDs(userIDs ...string) GroupCache {
new := g.NewCache()
var keys []string
for _, userID := range userIDs {
keys = append(keys, g.getJoinedSuperGroupsIDKey(userID))
}
new.AddKeys(keys...)
return new
}
func (g *GroupCacheRedis) DelSuperGroupMemberIDs(groupIDs ...string) GroupCache {
new := g.NewCache()
var keys []string
for _, groupID := range groupIDs {
keys = append(keys, g.getSuperGroupMemberIDsKey(groupID))
}
new.AddKeys(keys...)
return new
}
// groupMembersHash
func (g *GroupCacheRedis) GetGroupMembersHash(ctx context.Context, groupID string) (hashCode uint64, err error) {
return getCache(ctx, g.rcClient, g.getGroupMembersHashKey(groupID), g.expireTime, func(ctx context.Context) (uint64, error) {
userIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return 0, err
}
utils.Sort(userIDs, true)
bi := big.NewInt(0)
bi.SetString(utils.Md5(strings.Join(userIDs, ";"))[0:8], 16)
return bi.Uint64(), nil
})
}
func (g *GroupCacheRedis) GetGroupMemberHashMap(ctx context.Context, groupIDs []string) (map[string]*relationTb.GroupSimpleUserID, error) {
res := make(map[string]*relationTb.GroupSimpleUserID)
for _, groupID := range groupIDs {
hash, err := g.GetGroupMembersHash(ctx, groupID)
if err != nil {
return nil, err
}
num, err := g.GetGroupMemberNum(ctx, groupID)
if err != nil {
return nil, err
}
res[groupID] = &relationTb.GroupSimpleUserID{Hash: hash, MemberNum: uint32(num)}
}
return res, nil
}
func (g *GroupCacheRedis) DelGroupMembersHash(groupID string) GroupCache {
cache := g.NewCache()
cache.AddKeys(g.getGroupMembersHashKey(groupID))
return cache
}
// groupMemberIDs
func (g *GroupCacheRedis) GetGroupMemberIDs(ctx context.Context, groupID string) (groupMemberIDs []string, err error) {
return getCache(ctx, g.rcClient, g.getGroupMemberIDsKey(groupID), g.expireTime, func(ctx context.Context) ([]string, error) {
return g.groupMemberDB.FindMemberUserID(ctx, groupID)
})
}
func (g *GroupCacheRedis) GetGroupsMemberIDs(ctx context.Context, groupIDs []string) (map[string][]string, error) {
m := make(map[string][]string)
for _, groupID := range groupIDs {
userIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return nil, err
}
m[groupID] = userIDs
}
return m, nil
}
func (g *GroupCacheRedis) DelGroupMemberIDs(groupID string) GroupCache {
cache := g.NewCache()
cache.AddKeys(g.getGroupMemberIDsKey(groupID))
return cache
}
func (g *GroupCacheRedis) GetJoinedGroupIDs(ctx context.Context, userID string) (joinedGroupIDs []string, err error) {
return getCache(ctx, g.rcClient, g.getJoinedGroupsKey(userID), g.expireTime, func(ctx context.Context) ([]string, error) {
return g.groupMemberDB.FindUserJoinedGroupID(ctx, userID)
})
}
func (g *GroupCacheRedis) DelJoinedGroupID(userIDs ...string) GroupCache {
var keys []string
for _, userID := range userIDs {
keys = append(keys, g.getJoinedGroupsKey(userID))
}
cache := g.NewCache()
cache.AddKeys(keys...)
return cache
}
func (g *GroupCacheRedis) GetGroupMemberInfo(ctx context.Context, groupID, userID string) (groupMember *relationTb.GroupMemberModel, err error) {
return getCache(ctx, g.rcClient, g.getGroupMemberInfoKey(groupID, userID), g.expireTime, func(ctx context.Context) (*relationTb.GroupMemberModel, error) {
return g.groupMemberDB.Take(ctx, groupID, userID)
})
}
func (g *GroupCacheRedis) GetGroupMembersInfo(ctx context.Context, groupID string, userIDs []string) ([]*relationTb.GroupMemberModel, error) {
var keys []string
for _, userID := range userIDs {
keys = append(keys, g.getGroupMemberInfoKey(groupID, userID))
}
return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupMemberIndex, func(ctx context.Context) ([]*relationTb.GroupMemberModel, error) {
return g.groupMemberDB.Find(ctx, []string{groupID}, userIDs, nil)
})
}
func (g *GroupCacheRedis) GetGroupMembersPage(ctx context.Context, groupID string, userIDs []string, showNumber, pageNumber int32) (total uint32, groupMembers []*relationTb.GroupMemberModel, err error) {
groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return 0, nil, err
}
if userIDs != nil {
userIDs = utils.BothExist(userIDs, groupMemberIDs)
} else {
userIDs = groupMemberIDs
}
groupMembers, err = g.GetGroupMembersInfo(ctx, groupID, utils.Paginate(userIDs, int(showNumber), int(showNumber)))
return uint32(len(userIDs)), groupMembers, err
}
func (g *GroupCacheRedis) GetAllGroupMembersInfo(ctx context.Context, groupID string) (groupMembers []*relationTb.GroupMemberModel, err error) {
groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return nil, err
}
return g.GetGroupMembersInfo(ctx, groupID, groupMemberIDs)
}
func (g *GroupCacheRedis) GetAllGroupMemberInfo(ctx context.Context, groupID string) ([]*relationTb.GroupMemberModel, error) {
groupMemberIDs, err := g.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return nil, err
}
var keys []string
for _, groupMemberID := range groupMemberIDs {
keys = append(keys, g.getGroupMemberInfoKey(groupID, groupMemberID))
}
return batchGetCache(ctx, g.rcClient, keys, g.expireTime, g.GetGroupMemberIndex, func(ctx context.Context) ([]*relationTb.GroupMemberModel, error) {
return g.groupMemberDB.Find(ctx, []string{groupID}, groupMemberIDs, nil)
})
}
func (g *GroupCacheRedis) DelGroupMembersInfo(groupID string, userIDs ...string) GroupCache {
var keys []string
for _, userID := range userIDs {
keys = append(keys, g.getGroupMemberInfoKey(groupID, userID))
}
cache := g.NewCache()
cache.AddKeys(keys...)
return cache
}
func (g *GroupCacheRedis) GetGroupMemberNum(ctx context.Context, groupID string) (memberNum int64, err error) {
return getCache(ctx, g.rcClient, g.getGroupMemberNumKey(groupID), g.expireTime, func(ctx context.Context) (int64, error) {
return g.groupMemberDB.TakeGroupMemberNum(ctx, groupID)
})
}
func (g *GroupCacheRedis) DelGroupsMemberNum(groupID ...string) GroupCache {
var keys []string
for _, groupID := range groupID {
keys = append(keys, g.getGroupMemberNumKey(groupID))
}
cache := g.NewCache()
cache.AddKeys(keys...)
return cache
}
+44
View File
@@ -0,0 +1,44 @@
package cache
import (
"context"
"errors"
"fmt"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/mw/specialerror"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/redis/go-redis/v9"
)
func NewRedis() (redis.UniversalClient, error) {
if len(config.Config.Redis.Address) == 0 {
return nil, errors.New("redis address is empty")
}
specialerror.AddReplace(redis.Nil, errs.ErrRecordNotFound)
var rdb redis.UniversalClient
if len(config.Config.Redis.Address) > 1 {
rdb = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: config.Config.Redis.Address,
Username: config.Config.Redis.Username,
Password: config.Config.Redis.Password, // no password set
PoolSize: 50,
})
} else {
rdb = redis.NewClient(&redis.Options{
Addr: config.Config.Redis.Address[0],
Username: config.Config.Redis.Username,
Password: config.Config.Redis.Password, // no password set
DB: 0, // use default DB
PoolSize: 100, // 连接池大小
})
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
err := rdb.Ping(ctx).Err()
if err != nil {
return nil, fmt.Errorf("redis ping %w", err)
}
return rdb, nil
}
+191
View File
@@ -0,0 +1,191 @@
package cache
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
)
const (
scanCount = 3000
maxRetryTimes = 5
retryInterval = time.Millisecond * 100
)
var errIndex = errors.New("err index")
type metaCache interface {
ExecDel(ctx context.Context) error
// delete key rapid
DelKey(ctx context.Context, key string) error
AddKeys(keys ...string)
ClearKeys()
GetPreDelKeys() []string
}
func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
return &metaCacheRedis{rcClient: rcClient, keys: keys, maxRetryTimes: maxRetryTimes, retryInterval: retryInterval}
}
type metaCacheRedis struct {
rcClient *rockscache.Client
keys []string
maxRetryTimes int
retryInterval time.Duration
}
func (m *metaCacheRedis) ExecDel(ctx context.Context) error {
if len(m.keys) > 0 {
log.ZDebug(ctx, "delete cache", "keys", m.keys)
retryTimes := 0
for {
if err := m.rcClient.TagAsDeletedBatch2(ctx, m.keys); err != nil {
if retryTimes >= m.maxRetryTimes {
err = errs.ErrInternalServer.Wrap(fmt.Sprintf("delete cache error: %v, keys: %v, retry times %d, please check redis server", err, m.keys, retryTimes))
log.ZWarn(ctx, "delete cache failed, please handle keys", err, "keys", m.keys)
return err
}
retryTimes++
} else {
break
}
}
}
return nil
}
func (m *metaCacheRedis) DelKey(ctx context.Context, key string) error {
return m.rcClient.TagAsDeleted2(ctx, key)
}
func (m *metaCacheRedis) AddKeys(keys ...string) {
m.keys = append(m.keys, keys...)
}
func (m *metaCacheRedis) ClearKeys() {
m.keys = []string{}
}
func (m *metaCacheRedis) GetPreDelKeys() []string {
return m.keys
}
func GetDefaultOpt() rockscache.Options {
opts := rockscache.NewDefaultOptions()
opts.StrongConsistency = true
opts.RandomExpireAdjustment = 0.2
return opts
}
func getCache[T any](ctx context.Context, rcClient *rockscache.Client, key string, expire time.Duration, fn func(ctx context.Context) (T, error)) (T, error) {
var t T
var write bool
v, err := rcClient.Fetch2(ctx, key, expire, func() (s string, err error) {
t, err = fn(ctx)
if err != nil {
return "", err
}
bs, err := json.Marshal(t)
if err != nil {
return "", utils.Wrap(err, "")
}
write = true
return string(bs), nil
})
if err != nil {
return t, err
}
if write {
return t, nil
}
if v == "" {
return t, errs.ErrRecordNotFound.Wrap("cache is not found")
}
err = json.Unmarshal([]byte(v), &t)
if err != nil {
log.ZError(ctx, "cache json.Unmarshal failed", err, "key", key, "value", v, "expire", expire)
return t, utils.Wrap(err, "")
}
return t, nil
}
func batchGetCache[T any](ctx context.Context, rcClient *rockscache.Client, keys []string, expire time.Duration, keyIndexFn func(t T, keys []string) (int, error), fn func(ctx context.Context) ([]T, error)) ([]T, error) {
batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) {
values := make(map[int]string)
tArrays, err := fn(ctx)
if err != nil {
return nil, err
}
for _, v := range tArrays {
index, err := keyIndexFn(v, keys)
if err != nil {
continue
}
bs, err := json.Marshal(v)
if err != nil {
return nil, utils.Wrap(err, "marshal failed")
}
values[index] = string(bs)
}
return values, nil
})
if err != nil {
return nil, err
}
var tArrays []T
for _, v := range batchMap {
if v != "" {
var t T
err = json.Unmarshal([]byte(v), &t)
if err != nil {
return nil, utils.Wrap(err, "unmarshal failed")
}
tArrays = append(tArrays, t)
}
}
return tArrays, nil
}
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) {
batchMap, err := rcClient.FetchBatch2(ctx, keys, expire, func(idxs []int) (m map[int]string, err error) {
tArrays, err := fn(ctx)
if err != nil {
return nil, err
}
values := make(map[int]string)
for k, v := range tArrays {
index, err := keyIndexFn(k, originKeys)
if err != nil {
continue
}
bs, err := json.Marshal(v)
if err != nil {
return nil, utils.Wrap(err, "marshal failed")
}
values[index] = string(bs)
}
return values, nil
})
if err != nil {
return nil, err
}
tMap := make(map[string]T)
for i, v := range batchMap {
if v != "" {
var t T
err = json.Unmarshal([]byte(v), &t)
if err != nil {
return nil, utils.Wrap(err, "unmarshal failed")
}
tMap[originKeys[i]] = t
}
}
return tMap, nil
}
+577
View File
@@ -0,0 +1,577 @@
package cache
import (
"context"
"strconv"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/dtm-labs/rockscache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/gogo/protobuf/jsonpb"
"github.com/redis/go-redis/v9"
)
const (
maxSeq = "MAX_SEQ:"
minSeq = "MIN_SEQ:"
conversationUserMinSeq = "CON_USER_MIN_SEQ:"
hasReadSeq = "HAS_READ_SEQ:"
appleDeviceToken = "DEVICE_TOKEN"
getuiToken = "GETUI_TOKEN"
getuiTaskID = "GETUI_TASK_ID"
signalCache = "SIGNAL_CACHE:"
signalListCache = "SIGNAL_LIST_CACHE:"
fcmToken = "FCM_TOKEN:"
messageCache = "MESSAGE_CACHE:"
messageDelUserList = "MESSAGE_DEL_USER_LIST:"
userDelMessagesList = "USER_DEL_MESSAGES_LIST:"
sendMsgFailedFlag = "SEND_MSG_FAILED_FLAG:"
userBadgeUnreadCountSum = "USER_BADGE_UNREAD_COUNT_SUM:"
exTypeKeyLocker = "EX_LOCK:"
uidPidToken = "UID_PID_TOKEN_STATUS:"
)
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)
}
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)
}
type MsgModel interface {
SeqCache
thirdCache
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
GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsg []*sdkws.MsgData, failedSeqList []int64, err error)
SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error)
UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error
DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64)
DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error
GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error)
CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error
DelMsgFromCache(ctx context.Context, userID string, seqList []int64) error
SetSendMsgStatus(ctx context.Context, id string, status int32) error
GetSendMsgStatus(ctx context.Context, id string) (int32, error)
JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error)
GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error)
DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error
SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error)
GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error)
SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error
LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error
UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error
}
func NewMsgCacheModel(client redis.UniversalClient) MsgModel {
return &msgCache{rdb: client}
}
type msgCache struct {
metaCache
rdb redis.UniversalClient
expireTime time.Duration
rcClient *rockscache.Client
msgDocDatabase unRelationTb.MsgDocModelInterface
}
func (c *msgCache) getMaxSeqKey(conversationID string) string {
return maxSeq + conversationID
}
func (c *msgCache) getMinSeqKey(conversationID string) string {
return minSeq + conversationID
}
func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string {
return hasReadSeq + userID + ":" + conversationID
}
func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error {
return utils.Wrap1(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
}
func (c *msgCache) getSeq(ctx context.Context, conversationID string, getkey func(conversationID string) string) (int64, error) {
return utils.Wrap2(c.rdb.Get(ctx, getkey(conversationID)).Int64())
}
func (c *msgCache) getSeqs(ctx context.Context, items []string, getkey func(s string) string) (m map[string]int64, err error) {
pipe := c.rdb.Pipeline()
for _, v := range items {
if err := pipe.Get(ctx, getkey(v)).Err(); err != nil && err != redis.Nil {
return nil, errs.Wrap(err)
}
}
result, err := pipe.Exec(ctx)
if err != nil && err != redis.Nil {
return nil, errs.Wrap(err)
}
m = make(map[string]int64, len(items))
for i, v := range result {
seq := v.(*redis.StringCmd)
if seq.Err() != nil && seq.Err() != redis.Nil {
return nil, errs.Wrap(v.Err())
}
val := utils.StringToInt64(seq.Val())
if val != 0 {
m[items[i]] = val
}
}
return m, nil
}
func (c *msgCache) SetMaxSeq(ctx context.Context, conversationID string, maxSeq int64) error {
return c.setSeq(ctx, conversationID, maxSeq, c.getMaxSeqKey)
}
func (c *msgCache) GetMaxSeqs(ctx context.Context, conversationIDs []string) (m map[string]int64, err error) {
return c.getSeqs(ctx, conversationIDs, c.getMaxSeqKey)
}
func (c *msgCache) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) {
return c.getSeq(ctx, conversationID, c.getMaxSeqKey)
}
func (c *msgCache) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
return c.setSeq(ctx, conversationID, minSeq, c.getMinSeqKey)
}
func (c *msgCache) setSeqs(ctx context.Context, seqs map[string]int64, getkey func(key string) string) error {
pipe := c.rdb.Pipeline()
for k, seq := range seqs {
err := pipe.Set(ctx, getkey(k), seq, 0).Err()
if err != nil {
return errs.Wrap(err)
}
}
_, err := pipe.Exec(ctx)
return err
}
func (c *msgCache) SetMinSeqs(ctx context.Context, seqs map[string]int64) error {
return c.setSeqs(ctx, seqs, c.getMinSeqKey)
}
func (c *msgCache) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
return c.getSeqs(ctx, conversationIDs, c.getMinSeqKey)
}
func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64, error) {
return c.getSeq(ctx, conversationID, c.getMinSeqKey)
}
func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string {
return conversationUserMinSeq + conversationID + "u:" + userID
}
func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
return utils.Wrap2(c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64())
}
func (c *msgCache) 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 *msgCache) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error {
return utils.Wrap1(c.rdb.Set(ctx, c.getConversationUserMinSeqKey(conversationID, userID), minSeq, 0).Err())
}
func (c *msgCache) 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 *msgCache) 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 *msgCache) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error {
return utils.Wrap1(c.rdb.Set(ctx, c.getHasReadSeqKey(conversationID, userID), hasReadSeq, 0).Err())
}
func (c *msgCache) 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 *msgCache) 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 *msgCache) 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 *msgCache) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) {
return utils.Wrap2(c.rdb.Get(ctx, c.getHasReadSeqKey(conversationID, userID)).Int64())
}
func (c *msgCache) AddTokenFlag(ctx context.Context, userID string, platformID int, token string, flag int) error {
key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
return errs.Wrap(c.rdb.HSet(ctx, key, token, flag).Err())
}
func (c *msgCache) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID)
m, err := c.rdb.HGetAll(ctx, key).Result()
if err != nil {
return nil, errs.Wrap(err)
}
mm := make(map[string]int)
for k, v := range m {
mm[k] = utils.StringToInt(v)
}
return mm, nil
}
func (c *msgCache) SetTokenMapByUidPid(ctx context.Context, userID string, platform int, m map[string]int) error {
key := uidPidToken + userID + ":" + constant.PlatformIDToName(platform)
mm := make(map[string]interface{})
for k, v := range m {
mm[k] = v
}
return errs.Wrap(c.rdb.HSet(ctx, key, mm).Err())
}
func (c *msgCache) DeleteTokenByUidPid(ctx context.Context, userID string, platform int, fields []string) error {
key := uidPidToken + userID + ":" + constant.PlatformIDToName(platform)
return errs.Wrap(c.rdb.HDel(ctx, key, fields...).Err())
}
func (c *msgCache) getMessageCacheKey(conversationID string, seq int64) string {
return messageCache + conversationID + "_" + strconv.Itoa(int(seq))
}
func (c *msgCache) allMessageCacheKey(conversationID string) string {
return messageCache + conversationID + "_*"
}
func (c *msgCache) GetMessagesBySeq(ctx context.Context, conversationID string, seqs []int64) (seqMsgs []*sdkws.MsgData, failedSeqs []int64, err error) {
pipe := c.rdb.Pipeline()
for _, v := range seqs {
//MESSAGE_CACHE:169.254.225.224_reliability1653387820_0_1
key := c.getMessageCacheKey(conversationID, v)
if err := pipe.Get(ctx, key).Err(); err != nil && err != redis.Nil {
return nil, nil, err
}
}
result, err := pipe.Exec(ctx)
for i, v := range result {
cmd := v.(*redis.StringCmd)
if cmd.Err() != nil {
failedSeqs = append(failedSeqs, seqs[i])
} else {
msg := sdkws.MsgData{}
err = utils.String2Pb(cmd.Val(), &msg)
if err == nil {
if msg.Status != constant.MsgDeleted {
seqMsgs = append(seqMsgs, &msg)
continue
}
} else {
log.ZWarn(ctx, "UnmarshalString failed", err, "conversationID", conversationID, "seq", seqs[i], "msg", cmd.Val())
}
failedSeqs = append(failedSeqs, seqs[i])
}
}
return seqMsgs, failedSeqs, err
}
func (c *msgCache) SetMessageToCache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (int, error) {
pipe := c.rdb.Pipeline()
var failedMsgs []*sdkws.MsgData
for _, msg := range msgs {
key := c.getMessageCacheKey(conversationID, msg.Seq)
s, err := utils.Pb2String(msg)
if err != nil {
return 0, errs.Wrap(err)
}
err = pipe.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err()
if err != nil {
failedMsgs = append(failedMsgs, msg)
log.ZWarn(ctx, "set msg 2 cache failed", err, "msg", failedMsgs)
}
}
_, err := pipe.Exec(ctx)
return len(failedMsgs), err
}
func (c *msgCache) getMessageDelUserListKey(conversationID string, seq int64) string {
return messageDelUserList + conversationID + ":" + strconv.Itoa(int(seq))
}
func (c *msgCache) getUserDelList(conversationID, userID string) string {
return userDelMessagesList + conversationID + ":" + userID
}
func (c *msgCache) UserDeleteMsgs(ctx context.Context, conversationID string, seqs []int64, userID string) error {
pipe := c.rdb.Pipeline()
for _, seq := range seqs {
delUserListKey := c.getMessageDelUserListKey(conversationID, seq)
userDelListKey := c.getUserDelList(conversationID, userID)
err := pipe.SAdd(ctx, delUserListKey, userID).Err()
if err != nil {
return errs.Wrap(err)
}
err = pipe.SAdd(ctx, userDelListKey, seq).Err()
if err != nil {
return errs.Wrap(err)
}
if err := pipe.Expire(ctx, delUserListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
if err := pipe.Expire(ctx, userDelListKey, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
}
_, err := pipe.Exec(ctx)
return errs.Wrap(err)
}
func (c *msgCache) GetUserDelList(ctx context.Context, userID, conversationID string) (seqs []int64, err error) {
result, err := c.rdb.SMembers(ctx, c.getUserDelList(conversationID, userID)).Result()
if err != nil {
return nil, errs.Wrap(err)
}
seqs = make([]int64, len(result))
for i, v := range result {
seqs[i] = utils.StringToInt64(v)
}
return seqs, nil
}
func (c *msgCache) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) {
for _, seq := range seqs {
delUsers, err := c.rdb.SMembers(ctx, c.getMessageDelUserListKey(conversationID, seq)).Result()
if err != nil {
log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq)
continue
}
if len(delUsers) > 0 {
pipe := c.rdb.Pipeline()
var failedFlag bool
for _, userID := range delUsers {
err = pipe.SRem(ctx, c.getUserDelList(conversationID, userID), seq).Err()
if err != nil {
failedFlag = true
log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq, "userID", userID)
}
}
if !failedFlag {
if err := pipe.Del(ctx, c.getMessageDelUserListKey(conversationID, seq)).Err(); err != nil {
log.ZWarn(ctx, "DelUserDeleteMsgsList failed", err, "conversationID", conversationID, "seq", seq)
}
}
if _, err := pipe.Exec(ctx); err != nil {
log.ZError(ctx, "pipe exec failed", err, "conversationID", conversationID, "seq", seq)
}
}
}
}
func (c *msgCache) DeleteMessages(ctx context.Context, conversationID string, seqs []int64) error {
pipe := c.rdb.Pipeline()
for _, seq := range seqs {
if err := pipe.Del(ctx, c.getMessageCacheKey(conversationID, seq)).Err(); err != nil {
return errs.Wrap(err)
}
}
_, err := pipe.Exec(ctx)
return errs.Wrap(err)
}
func (c *msgCache) CleanUpOneConversationAllMsg(ctx context.Context, conversationID string) error {
vals, err := c.rdb.Keys(ctx, c.allMessageCacheKey(conversationID)).Result()
if err == redis.Nil {
return nil
}
if err != nil {
return errs.Wrap(err)
}
pipe := c.rdb.Pipeline()
for _, v := range vals {
if err := pipe.Del(ctx, v).Err(); err != nil {
return errs.Wrap(err)
}
}
_, err = pipe.Exec(ctx)
return errs.Wrap(err)
}
func (c *msgCache) DelMsgFromCache(ctx context.Context, userID string, seqs []int64) error {
for _, seq := range seqs {
key := c.getMessageCacheKey(userID, seq)
result, err := c.rdb.Get(ctx, key).Result()
if err != nil {
if err == redis.Nil {
continue
}
return errs.Wrap(err)
}
var msg sdkws.MsgData
if err := jsonpb.UnmarshalString(result, &msg); err != nil {
return err
}
msg.Status = constant.MsgDeleted
s, err := utils.Pb2String(&msg)
if err != nil {
return errs.Wrap(err)
}
if err := c.rdb.Set(ctx, key, s, time.Duration(config.Config.MsgCacheTimeout)*time.Second).Err(); err != nil {
return errs.Wrap(err)
}
}
return nil
}
func (c *msgCache) 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 *msgCache) GetGetuiToken(ctx context.Context) (string, error) {
return utils.Wrap2(c.rdb.Get(ctx, getuiToken).Result())
}
func (c *msgCache) 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 *msgCache) GetGetuiTaskID(ctx context.Context) (string, error) {
return utils.Wrap2(c.rdb.Get(ctx, getuiTaskID).Result())
}
func (c *msgCache) SetSendMsgStatus(ctx context.Context, id string, status int32) error {
return errs.Wrap(c.rdb.Set(ctx, sendMsgFailedFlag+id, status, time.Hour*24).Err())
}
func (c *msgCache) GetSendMsgStatus(ctx context.Context, id string) (int32, error) {
result, err := c.rdb.Get(ctx, sendMsgFailedFlag+id).Int()
return int32(result), errs.Wrap(err)
}
func (c *msgCache) SetFcmToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) (err error) {
return errs.Wrap(c.rdb.Set(ctx, fcmToken+account+":"+strconv.Itoa(platformID), fcmToken, time.Duration(expireTime)*time.Second).Err())
}
func (c *msgCache) GetFcmToken(ctx context.Context, account string, platformID int) (string, error) {
return utils.Wrap2(c.rdb.Get(ctx, fcmToken+account+":"+strconv.Itoa(platformID)).Result())
}
func (c *msgCache) DelFcmToken(ctx context.Context, account string, platformID int) error {
return errs.Wrap(c.rdb.Del(ctx, fcmToken+account+":"+strconv.Itoa(platformID)).Err())
}
func (c *msgCache) 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 *msgCache) SetUserBadgeUnreadCountSum(ctx context.Context, userID string, value int) error {
return errs.Wrap(c.rdb.Set(ctx, userBadgeUnreadCountSum+userID, value, 0).Err())
}
func (c *msgCache) GetUserBadgeUnreadCountSum(ctx context.Context, userID string) (int, error) {
return utils.Wrap2(c.rdb.Get(ctx, userBadgeUnreadCountSum+userID).Int())
}
func (c *msgCache) LockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error {
key := exTypeKeyLocker + clientMsgID + "_" + TypeKey
return errs.Wrap(c.rdb.SetNX(ctx, key, 1, time.Minute).Err())
}
func (c *msgCache) UnLockMessageTypeKey(ctx context.Context, clientMsgID string, TypeKey string) error {
key := exTypeKeyLocker + clientMsgID + "_" + TypeKey
return errs.Wrap(c.rdb.Del(ctx, key).Err())
}
func (c *msgCache) getMessageReactionExPrefix(clientMsgID string, sessionType int32) string {
switch sessionType {
case constant.SingleChatType:
return "EX_SINGLE_" + clientMsgID
case constant.GroupChatType:
return "EX_GROUP_" + clientMsgID
case constant.SuperGroupChatType:
return "EX_SUPER_GROUP_" + clientMsgID
case constant.NotificationChatType:
return "EX_NOTIFICATION" + clientMsgID
}
return ""
}
func (c *msgCache) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) {
n, err := c.rdb.Exists(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result()
if err != nil {
return false, utils.Wrap(err, "")
}
return n > 0, nil
}
func (c *msgCache) SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error {
return errs.Wrap(c.rdb.HSet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey, value).Err())
}
func (c *msgCache) SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) {
return utils.Wrap2(c.rdb.Expire(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), expiration).Result())
}
func (c *msgCache) GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) {
return utils.Wrap2(c.rdb.HGet(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), typeKey).Result())
}
func (c *msgCache) GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) {
return utils.Wrap2(c.rdb.HGetAll(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType)).Result())
}
func (c *msgCache) DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error {
return errs.Wrap(c.rdb.HDel(ctx, c.getMessageReactionExPrefix(clientMsgID, sessionType), subKey).Err())
}
+109
View File
@@ -0,0 +1,109 @@
package cache
import (
"context"
"time"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
)
const (
userExpireTime = time.Second * 60 * 60 * 12
userInfoKey = "USER_INFO:"
userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
)
type UserCache interface {
metaCache
NewCache() UserCache
GetUserInfo(ctx context.Context, userID string) (userInfo *relationTb.UserModel, err error)
GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationTb.UserModel, error)
DelUsersInfo(userIDs ...string) UserCache
GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error)
DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache
}
type UserCacheRedis struct {
metaCache
userDB relationTb.UserModelInterface
expireTime time.Duration
rcClient *rockscache.Client
}
func NewUserCacheRedis(rdb redis.UniversalClient, userDB relationTb.UserModelInterface, options rockscache.Options) UserCache {
rcClient := rockscache.NewClient(rdb, options)
return &UserCacheRedis{
metaCache: NewMetaCacheRedis(rcClient),
userDB: userDB,
expireTime: userExpireTime,
rcClient: rcClient,
}
}
func (u *UserCacheRedis) NewCache() UserCache {
return &UserCacheRedis{
metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...),
userDB: u.userDB,
expireTime: u.expireTime,
rcClient: u.rcClient,
}
}
func (u *UserCacheRedis) getUserInfoKey(userID string) string {
return userInfoKey + userID
}
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
return userGlobalRecvMsgOptKey + userID
}
func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationTb.UserModel, err error) {
return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationTb.UserModel, error) {
return u.userDB.Take(ctx, userID)
})
}
func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationTb.UserModel, error) {
var keys []string
for _, userID := range userIDs {
keys = append(keys, u.getUserInfoKey(userID))
}
return batchGetCache(ctx, u.rcClient, keys, u.expireTime, func(user *relationTb.UserModel, keys []string) (int, error) {
for i, key := range keys {
if key == u.getUserInfoKey(user.UserID) {
return i, nil
}
}
return 0, errIndex
}, func(ctx context.Context) ([]*relationTb.UserModel, error) {
return u.userDB.Find(ctx, userIDs)
})
}
func (u *UserCacheRedis) DelUsersInfo(userIDs ...string) UserCache {
var keys []string
for _, userID := range userIDs {
keys = append(keys, u.getUserInfoKey(userID))
}
cache := u.NewCache()
cache.AddKeys(keys...)
return cache
}
func (u *UserCacheRedis) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
return getCache(ctx, u.rcClient, u.getUserGlobalRecvMsgOptKey(userID), u.expireTime, func(ctx context.Context) (int, error) {
return u.userDB.GetUserGlobalRecvMsgOpt(ctx, userID)
})
}
func (u *UserCacheRedis) DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache {
var keys []string
for _, userID := range userIDs {
keys = append(keys, u.getUserGlobalRecvMsgOptKey(userID))
}
cache := u.NewCache()
cache.AddKeys(keys...)
return cache
}
+62
View File
@@ -0,0 +1,62 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/tokenverify"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/golang-jwt/jwt/v4"
)
type AuthDatabase interface {
//结果为空 不返回错误
GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error)
//创建token
CreateToken(ctx context.Context, userID string, platformID int) (string, error)
}
type authDatabase struct {
cache cache.MsgModel
accessSecret string
accessExpire int64
}
func NewAuthDatabase(cache cache.MsgModel, accessSecret string, accessExpire int64) AuthDatabase {
return &authDatabase{cache: cache, accessSecret: accessSecret, accessExpire: accessExpire}
}
// 结果为空 不返回错误
func (a *authDatabase) GetTokensWithoutError(ctx context.Context, userID string, platformID int) (map[string]int, error) {
return a.cache.GetTokensWithoutError(ctx, userID, platformID)
}
// 创建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 {
return "", err
}
var deleteTokenKey []string
for k, v := range tokens {
_, err = tokenverify.GetClaimFromToken(k)
if err != nil || v != constant.NormalToken {
deleteTokenKey = append(deleteTokenKey, k)
}
}
if len(deleteTokenKey) != 0 {
err := a.cache.DeleteTokenByUidPid(ctx, userID, platformID, deleteTokenKey)
if err != nil {
return "", err
}
}
claims := tokenverify.BuildClaims(userID, platformID, a.accessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.accessSecret))
if err != nil {
return "", utils.Wrap(err, "")
}
return tokenString, a.cache.AddTokenFlag(ctx, userID, platformID, tokenString, constant.NormalToken)
}
+78
View File
@@ -0,0 +1,78 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
)
type BlackDatabase interface {
// Create 增加黑名单
Create(ctx context.Context, blacks []*relation.BlackModel) (err error)
// Delete 删除黑名单
Delete(ctx context.Context, blacks []*relation.BlackModel) (err error)
// FindOwnerBlacks 获取黑名单列表
FindOwnerBlacks(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (blacks []*relation.BlackModel, total int64, err error)
FindBlackIDs(ctx context.Context, ownerUserID string) (blackIDs []string, err error)
// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true)
CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error)
}
type blackDatabase struct {
black relation.BlackModelInterface
cache cache.BlackCache
}
func NewBlackDatabase(black relation.BlackModelInterface, cache cache.BlackCache) BlackDatabase {
return &blackDatabase{black, cache}
}
// Create 增加黑名单
func (b *blackDatabase) Create(ctx context.Context, blacks []*relation.BlackModel) (err error) {
if err := b.black.Create(ctx, blacks); err != nil {
return err
}
return b.deleteBlackIDsCache(ctx, blacks)
}
// Delete 删除黑名单
func (b *blackDatabase) Delete(ctx context.Context, blacks []*relation.BlackModel) (err error) {
if err := b.black.Delete(ctx, blacks); err != nil {
return err
}
return b.deleteBlackIDsCache(ctx, blacks)
}
func (b *blackDatabase) deleteBlackIDsCache(ctx context.Context, blacks []*relation.BlackModel) (err error) {
cache := b.cache.NewCache()
for _, black := range blacks {
cache = cache.DelBlackIDs(ctx, black.OwnerUserID)
}
return cache.ExecDel(ctx)
}
// FindOwnerBlacks 获取黑名单列表
func (b *blackDatabase) FindOwnerBlacks(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (blacks []*relation.BlackModel, total int64, err error) {
return b.black.FindOwnerBlacks(ctx, ownerUserID, pageNumber, showNumber)
}
// CheckIn 检查user2是否在user1的黑名单列表中(inUser1Blacks==true) 检查user1是否在user2的黑名单列表中(inUser2Blacks==true)
func (b *blackDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Blacks bool, inUser2Blacks bool, err error) {
userID1BlackIDs, err := b.cache.GetBlackIDs(ctx, userID1)
if err != nil {
return
}
userID2BlackIDs, err := b.cache.GetBlackIDs(ctx, userID2)
if err != nil {
return
}
log.ZDebug(ctx, "blackIDs", "user1BlackIDs", userID1BlackIDs, "user2BlackIDs", userID2BlackIDs)
return utils.IsContain(userID2, userID1BlackIDs), utils.IsContain(userID1, userID2BlackIDs), nil
}
func (b *blackDatabase) FindBlackIDs(ctx context.Context, ownerUserID string) (blackIDs []string, err error) {
return b.cache.GetBlackIDs(ctx, ownerUserID)
}
+27
View File
@@ -0,0 +1,27 @@
package controller
import (
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
pbMsg "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/msg"
)
type ChatLogDatabase interface {
CreateChatLog(msg *pbMsg.MsgDataToMQ) error
GetChatLog(chatLog *relationTb.ChatLogModel, pageNumber, showNumber int32, contentTypes []int32) (int64, []relationTb.ChatLogModel, error)
}
func NewChatLogDatabase(chatLogModelInterface relationTb.ChatLogModelInterface) ChatLogDatabase {
return &chatLogDatabase{chatLogModel: chatLogModelInterface}
}
type chatLogDatabase struct {
chatLogModel relationTb.ChatLogModelInterface
}
func (c *chatLogDatabase) CreateChatLog(msg *pbMsg.MsgDataToMQ) error {
return c.chatLogModel.Create(msg)
}
func (c *chatLogDatabase) GetChatLog(chatLog *relationTb.ChatLogModel, pageNumber, showNumber int32, contentTypes []int32) (int64, []relationTb.ChatLogModel, error) {
return c.chatLogModel.GetChatLog(chatLog, pageNumber, showNumber, contentTypes)
}
+271
View File
@@ -0,0 +1,271 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
)
type ConversationDatabase interface {
//UpdateUserConversationFiled 更新用户该会话的属性信息
UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) error
//CreateConversation 创建一批新的会话
CreateConversation(ctx context.Context, conversations []*relationTb.ConversationModel) error
//SyncPeerUserPrivateConversation 同步对端私聊会话内部保证事务操作
SyncPeerUserPrivateConversationTx(ctx context.Context, conversation []*relationTb.ConversationModel) error
//FindConversations 根据会话ID获取某个用户的多个会话
FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationTb.ConversationModel, error)
//FindRecvMsgNotNotifyUserIDs 获取超级大群开启免打扰的用户ID
FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
//GetUserAllConversation 获取一个用户在服务器上所有的会话
GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationTb.ConversationModel, error)
//SetUserConversations 设置用户多个会话属性,如果会话不存在则创建,否则更新,内部保证原子性
SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationTb.ConversationModel) error
//SetUsersConversationFiledTx 设置多个用户会话关于某个字段的更新操作,如果会话不存在则创建,否则更新,内部保证事务操作
SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationTb.ConversationModel, filedMap map[string]interface{}) error
CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error
GetConversationIDs(ctx context.Context, userID string) ([]string, error)
GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error)
GetAllConversationIDs(ctx context.Context) ([]string, error)
GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error)
GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationTb.ConversationModel, error)
}
func NewConversationDatabase(conversation relationTb.ConversationModelInterface, cache cache.ConversationCache, tx tx.Tx) ConversationDatabase {
return &conversationDatabase{
conversationDB: conversation,
cache: cache,
tx: tx,
}
}
type conversationDatabase struct {
conversationDB relationTb.ConversationModelInterface
cache cache.ConversationCache
tx tx.Tx
}
func (c *conversationDatabase) SetUsersConversationFiledTx(ctx context.Context, userIDs []string, conversation *relationTb.ConversationModel, filedMap map[string]interface{}) (err error) {
cache := c.cache.NewCache()
if err := c.tx.Transaction(func(tx any) error {
conversationTx := c.conversationDB.NewTx(tx)
haveUserIDs, err := conversationTx.FindUserID(ctx, userIDs, []string{conversation.ConversationID})
if err != nil {
return err
}
if len(haveUserIDs) > 0 {
_, err = conversationTx.UpdateByMap(ctx, haveUserIDs, conversation.ConversationID, filedMap)
if err != nil {
return err
}
cache = cache.DelUsersConversation(conversation.ConversationID, haveUserIDs...)
if _, ok := filedMap["has_read_seq"]; ok {
for _, userID := range haveUserIDs {
cache = cache.DelUserAllHasReadSeqs(userID, conversation.ConversationID)
}
}
}
NotUserIDs := utils.DifferenceString(haveUserIDs, userIDs)
log.ZDebug(ctx, "SetUsersConversationFiledTx", "NotUserIDs", NotUserIDs, "haveUserIDs", haveUserIDs, "userIDs", userIDs)
var conversations []*relationTb.ConversationModel
for _, v := range NotUserIDs {
temp := new(relationTb.ConversationModel)
if err := utils.CopyStructFields(temp, conversation); err != nil {
return err
}
temp.OwnerUserID = v
conversations = append(conversations, temp)
}
if len(conversations) > 0 {
err = conversationTx.Create(ctx, conversations)
if err != nil {
return err
}
cache = cache.DelConversationIDs(NotUserIDs...).DelUserConversationIDsHash(NotUserIDs...)
}
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (c *conversationDatabase) UpdateUsersConversationFiled(ctx context.Context, userIDs []string, conversationID string, args map[string]interface{}) error {
_, err := c.conversationDB.UpdateByMap(ctx, userIDs, conversationID, args)
if err != nil {
return err
}
return c.cache.DelUsersConversation(conversationID, userIDs...).ExecDel(ctx)
}
func (c *conversationDatabase) CreateConversation(ctx context.Context, conversations []*relationTb.ConversationModel) error {
if err := c.conversationDB.Create(ctx, conversations); err != nil {
return err
}
var userIDs []string
cache := c.cache.NewCache()
for _, conversation := range conversations {
cache = cache.DelConvsersations(conversation.OwnerUserID, conversation.ConversationID)
userIDs = append(userIDs, conversation.OwnerUserID)
}
return cache.DelConversationIDs(userIDs...).DelUserConversationIDsHash(userIDs...).ExecDel(ctx)
}
func (c *conversationDatabase) SyncPeerUserPrivateConversationTx(ctx context.Context, conversations []*relationTb.ConversationModel) error {
cache := c.cache.NewCache()
if err := c.tx.Transaction(func(tx any) error {
conversationTx := c.conversationDB.NewTx(tx)
for _, conversation := range conversations {
for _, v := range [][2]string{{conversation.OwnerUserID, conversation.UserID}, {conversation.UserID, conversation.OwnerUserID}} {
haveUserIDs, err := conversationTx.FindUserID(ctx, []string{v[0]}, []string{conversation.ConversationID})
if err != nil {
return err
}
if len(haveUserIDs) > 0 {
_, err := conversationTx.UpdateByMap(ctx, []string{v[0]}, conversation.ConversationID, map[string]interface{}{"is_private_chat": conversation.IsPrivateChat})
if err != nil {
return err
}
cache = cache.DelUsersConversation(conversation.ConversationID, v[0])
} else {
newConversation := *conversation
newConversation.OwnerUserID = v[0]
newConversation.UserID = v[1]
newConversation.ConversationID = conversation.ConversationID
newConversation.IsPrivateChat = conversation.IsPrivateChat
if err := conversationTx.Create(ctx, []*relationTb.ConversationModel{&newConversation}); err != nil {
return err
}
cache = cache.DelConversationIDs(v[0]).DelUserConversationIDsHash(v[0])
}
}
}
return nil
}); err != nil {
return err
}
return c.cache.ExecDel(ctx)
}
func (c *conversationDatabase) FindConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*relationTb.ConversationModel, error) {
return c.cache.GetConversations(ctx, ownerUserID, conversationIDs)
}
func (c *conversationDatabase) GetConversation(ctx context.Context, ownerUserID string, conversationID string) (*relationTb.ConversationModel, error) {
return c.cache.GetConversation(ctx, ownerUserID, conversationID)
}
func (c *conversationDatabase) GetUserAllConversation(ctx context.Context, ownerUserID string) ([]*relationTb.ConversationModel, error) {
return c.cache.GetUserAllConversations(ctx, ownerUserID)
}
func (c *conversationDatabase) SetUserConversations(ctx context.Context, ownerUserID string, conversations []*relationTb.ConversationModel) error {
cache := c.cache.NewCache()
if err := c.tx.Transaction(func(tx any) error {
var conversationIDs []string
for _, conversation := range conversations {
conversationIDs = append(conversationIDs, conversation.ConversationID)
}
conversationTx := c.conversationDB.NewTx(tx)
existConversations, err := conversationTx.Find(ctx, ownerUserID, conversationIDs)
if err != nil {
return err
}
if len(existConversations) > 0 {
for _, conversation := range conversations {
err = conversationTx.Update(ctx, conversation)
if err != nil {
return err
}
}
}
var existConversationIDs []string
for _, conversation := range existConversations {
existConversationIDs = append(existConversationIDs, conversation.ConversationID)
}
var notExistConversations []*relationTb.ConversationModel
for _, conversation := range conversations {
if !utils.IsContain(conversation.ConversationID, existConversationIDs) {
notExistConversations = append(notExistConversations, conversation)
}
}
if len(notExistConversations) > 0 {
err = c.conversationDB.Create(ctx, notExistConversations)
if err != nil {
return err
}
cache = cache.DelConversationIDs(ownerUserID).DelUserConversationIDsHash(ownerUserID)
}
cache = cache.DelConvsersations(ownerUserID, existConversationIDs...)
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (c *conversationDatabase) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
return c.cache.GetSuperGroupRecvMsgNotNotifyUserIDs(ctx, groupID)
}
func (c *conversationDatabase) CreateGroupChatConversation(ctx context.Context, groupID string, userIDs []string) error {
cache := c.cache.NewCache()
conversationID := utils.GetConversationIDBySessionType(constant.SuperGroupChatType, groupID)
if err := c.tx.Transaction(func(tx any) error {
existConversationUserIDs, err := c.conversationDB.FindUserID(ctx, userIDs, []string{conversationID})
if err != nil {
return err
}
notExistUserIDs := utils.DifferenceString(userIDs, existConversationUserIDs)
var conversations []*relationTb.ConversationModel
for _, v := range notExistUserIDs {
conversation := relationTb.ConversationModel{ConversationType: constant.SuperGroupChatType, GroupID: groupID, OwnerUserID: v, ConversationID: conversationID}
conversations = append(conversations, &conversation)
}
cache = cache.DelConversationIDs(notExistUserIDs...).DelUserConversationIDsHash(notExistUserIDs...)
if len(conversations) > 0 {
err = c.conversationDB.Create(ctx, conversations)
if err != nil {
return err
}
}
_, err = c.conversationDB.UpdateByMap(ctx, existConversationUserIDs, conversationID, map[string]interface{}{"max_seq": 0})
if err != nil {
return err
}
for _, v := range existConversationUserIDs {
cache = cache.DelConvsersations(v, conversationID)
}
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (c *conversationDatabase) GetConversationIDs(ctx context.Context, userID string) ([]string, error) {
return c.cache.GetUserConversationIDs(ctx, userID)
}
func (c *conversationDatabase) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) {
return c.cache.GetUserConversationIDsHash(ctx, ownerUserID)
}
func (c *conversationDatabase) GetAllConversationIDs(ctx context.Context) ([]string, error) {
return c.conversationDB.GetAllConversationIDs(ctx)
}
func (c *conversationDatabase) GetUserAllHasReadSeqs(ctx context.Context, ownerUserID string) (map[string]int64, error) {
return c.cache.GetUserAllHasReadSeqs(ctx, ownerUserID)
}
func (c *conversationDatabase) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*relationTb.ConversationModel, error) {
return c.conversationDB.GetConversationsByConversationID(ctx, conversationIDs)
}
+58
View File
@@ -0,0 +1,58 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/tx"
)
// for mongoDB
type ExtendMsgDatabase interface {
CreateExtendMsgSet(ctx context.Context, set *unRelationTb.ExtendMsgSetModel) error
GetAllExtendMsgSet(ctx context.Context, ID string, opts *unRelationTb.GetAllExtendMsgSetOpts) (sets []*unRelationTb.ExtendMsgSetModel, err error)
GetExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, maxMsgUpdateTime int64) (*unRelationTb.ExtendMsgSetModel, error)
InsertExtendMsg(ctx context.Context, conversationID string, sessionType int32, msg *unRelationTb.ExtendMsgModel) error
InsertOrUpdateReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*unRelationTb.KeyValueModel) error
DeleteReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*unRelationTb.KeyValueModel) error
GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, maxMsgUpdateTime int64) (extendMsg *unRelationTb.ExtendMsgModel, err error)
}
type extendMsgDatabase struct {
database unRelationTb.ExtendMsgSetModelInterface
cache cache.ExtendMsgSetCache
ctxTx tx.CtxTx
}
func NewExtendMsgDatabase(extendMsgModel unRelationTb.ExtendMsgSetModelInterface, cache cache.ExtendMsgSetCache, ctxTx tx.CtxTx) ExtendMsgDatabase {
return &extendMsgDatabase{database: extendMsgModel, cache: cache, ctxTx: ctxTx}
}
func (e *extendMsgDatabase) CreateExtendMsgSet(ctx context.Context, set *unRelationTb.ExtendMsgSetModel) error {
return e.database.CreateExtendMsgSet(ctx, set)
}
func (e *extendMsgDatabase) GetAllExtendMsgSet(ctx context.Context, conversationID string, opts *unRelationTb.GetAllExtendMsgSetOpts) (sets []*unRelationTb.ExtendMsgSetModel, err error) {
return e.database.GetAllExtendMsgSet(ctx, conversationID, opts)
}
func (e *extendMsgDatabase) GetExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, maxMsgUpdateTime int64) (*unRelationTb.ExtendMsgSetModel, error) {
return e.database.GetExtendMsgSet(ctx, conversationID, sessionType, maxMsgUpdateTime)
}
func (e *extendMsgDatabase) InsertExtendMsg(ctx context.Context, conversationID string, sessionType int32, msg *unRelationTb.ExtendMsgModel) error {
return e.database.InsertExtendMsg(ctx, conversationID, sessionType, msg)
}
func (e *extendMsgDatabase) InsertOrUpdateReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*unRelationTb.KeyValueModel) error {
return e.database.InsertOrUpdateReactionExtendMsgSet(ctx, conversationID, sessionType, clientMsgID, msgFirstModifyTime, reactionExtensionList)
}
func (e *extendMsgDatabase) DeleteReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*unRelationTb.KeyValueModel) error {
return e.database.DeleteReactionExtendMsgSet(ctx, conversationID, sessionType, clientMsgID, msgFirstModifyTime, reactionExtensionList)
}
func (e *extendMsgDatabase) GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, maxMsgUpdateTime int64) (extendMsg *unRelationTb.ExtendMsgModel, err error) {
return e.cache.GetExtendMsg(ctx, conversationID, sessionType, clientMsgID, maxMsgUpdateTime)
}
+252
View File
@@ -0,0 +1,252 @@
package controller
import (
"context"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/mcontext"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"gorm.io/gorm"
)
type FriendDatabase interface {
// 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true)
CheckIn(ctx context.Context, user1, user2 string) (inUser1Friends bool, inUser2Friends bool, err error)
// 增加或者更新好友申请
AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error)
// 先判断是否在好友表,如果在则不插入
BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error)
// 拒绝好友申请
RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error)
// 同意好友申请
AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error)
// 删除好友
Delete(ctx context.Context, ownerUserID string, friendUserIDs []string) (err error)
// 更新好友备注
UpdateRemark(ctx context.Context, ownerUserID, friendUserID, remark string) (err error)
// 获取ownerUserID的好友列表
PageOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (friends []*relation.FriendModel, total int64, err error)
// friendUserID在哪些人的好友列表中
PageInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) (friends []*relation.FriendModel, total int64, err error)
// 获取我发出去的好友申请
PageFriendRequestFromMe(ctx context.Context, userID string, pageNumber, showNumber int32) (friends []*relation.FriendRequestModel, total int64, err error)
// 获取我收到的的好友申请
PageFriendRequestToMe(ctx context.Context, userID string, pageNumber, showNumber int32) (friends []*relation.FriendRequestModel, total int64, err error)
// 获取某人指定好友的信息
FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error)
FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error)
}
type friendDatabase struct {
friend relation.FriendModelInterface
friendRequest relation.FriendRequestModelInterface
tx tx.Tx
cache cache.FriendCache
}
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}
}
// ok 检查user2是否在user1的好友列表中(inUser1Friends==true) 检查user1是否在user2的好友列表中(inUser2Friends==true)
func (f *friendDatabase) CheckIn(ctx context.Context, userID1, userID2 string) (inUser1Friends bool, inUser2Friends bool, err error) {
userID1FriendIDs, err := f.cache.GetFriendIDs(ctx, userID1)
if err != nil {
return
}
userID2FriendIDs, err := f.cache.GetFriendIDs(ctx, userID2)
if err != nil {
return
}
return utils.IsContain(userID2, userID1FriendIDs), utils.IsContain(userID1, userID2FriendIDs), nil
}
// 增加或者更新好友申请 如果之前有记录则更新,没有记录则新增
func (f *friendDatabase) AddFriendRequest(ctx context.Context, fromUserID, toUserID string, reqMsg string, ex string) (err error) {
return f.tx.Transaction(func(tx any) error {
_, err := f.friendRequest.NewTx(tx).Take(ctx, fromUserID, toUserID)
//有db错误
if err != nil && errs.Unwrap(err) != gorm.ErrRecordNotFound {
return err
}
//无错误 则更新
if err == nil {
m := make(map[string]interface{}, 1)
m["handle_result"] = 0
m["handle_msg"] = ""
m["req_msg"] = reqMsg
m["ex"] = ex
m["create_time"] = time.Now()
if err := f.friendRequest.NewTx(tx).UpdateByMap(ctx, fromUserID, toUserID, m); err != nil {
return err
}
return nil
}
//gorm.ErrRecordNotFound 错误,则新增
if err := f.friendRequest.NewTx(tx).Create(ctx, []*relation.FriendRequestModel{{FromUserID: fromUserID, ToUserID: toUserID, ReqMsg: reqMsg, Ex: ex, CreateTime: time.Now(), HandleTime: time.Unix(0, 0)}}); err != nil {
return err
}
return nil
})
}
// (1)先判断是否在好友表 (在不在都不返回错误) (2)对于不在好友列表的 插入即可
func (f *friendDatabase) BecomeFriends(ctx context.Context, ownerUserID string, friendUserIDs []string, addSource int32) (err error) {
cache := f.cache.NewCache()
if err := f.tx.Transaction(func(tx any) error {
//先find 找出重复的 去掉重复的
fs1, err := f.friend.NewTx(tx).FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil {
return err
}
opUserID := mcontext.GetOperationID(ctx)
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 {
return e.FriendUserID
})
err = f.friend.NewTx(tx).Create(ctx, fs11)
if err != nil {
return err
}
fs2, err := f.friend.NewTx(tx).FindReversalFriends(ctx, ownerUserID, friendUserIDs)
if err != nil {
return err
}
var newFriendIDs []string
for _, v := range friendUserIDs {
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 {
return e.OwnerUserID
})
err = f.friend.NewTx(tx).Create(ctx, fs22)
if err != nil {
return err
}
newFriendIDs = append(newFriendIDs, ownerUserID)
cache = cache.DelFriendIDs(newFriendIDs...)
return nil
}); err != nil {
return nil
}
return cache.ExecDel(ctx)
}
// 拒绝好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)修改申请记录 已拒绝
func (f *friendDatabase) RefuseFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
fr, err := f.friendRequest.Take(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil {
return err
}
if fr.HandleResult != 0 {
return errs.ErrArgs.Wrap("the friend request has been processed")
}
friendRequest.HandleResult = constant.FriendResponseRefuse
friendRequest.HandleTime = time.Now()
err = f.friendRequest.Update(ctx, friendRequest)
if err != nil {
return err
}
return nil
}
// AgreeFriendRequest 同意好友申请 (1)检查是否有申请记录且为未处理状态 (没有记录返回错误) (2)检查是否好友(不返回错误) (3) 建立双向好友关系(存在的忽略)
func (f *friendDatabase) AgreeFriendRequest(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
return f.tx.Transaction(func(tx any) error {
fr, err := f.friendRequest.NewTx(tx).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")
}
friendRequest.HandlerUserID = mcontext.GetOpUserID(ctx)
friendRequest.HandleResult = constant.FriendResponseAgree
friendRequest.HandleTime = time.Now()
err = f.friendRequest.NewTx(tx).Update(ctx, friendRequest)
if err != nil {
return err
}
exists, err := f.friend.NewTx(tx).FindUserState(ctx, friendRequest.FromUserID, friendRequest.ToUserID)
if err != nil {
return err
}
existsMap := utils.SliceSet(utils.Slice(exists, func(friend *relation.FriendModel) [2]string {
return [...]string{friend.OwnerUserID, friend.FriendUserID} // 自己 - 好友
}))
var adds []*relation.FriendModel
if _, ok := existsMap[[...]string{friendRequest.ToUserID, friendRequest.FromUserID}]; !ok { // 自己 - 好友
adds = append(adds, &relation.FriendModel{OwnerUserID: friendRequest.ToUserID, FriendUserID: friendRequest.FromUserID, AddSource: int32(constant.BecomeFriendByApply), OperatorUserID: friendRequest.FromUserID})
}
if _, ok := existsMap[[...]string{friendRequest.FromUserID, friendRequest.ToUserID}]; !ok { // 好友 - 自己
adds = append(adds, &relation.FriendModel{OwnerUserID: friendRequest.FromUserID, FriendUserID: friendRequest.ToUserID, AddSource: int32(constant.BecomeFriendByApply), OperatorUserID: friendRequest.FromUserID})
}
if len(adds) > 0 {
if err := f.friend.NewTx(tx).Create(ctx, adds); err != nil {
return err
}
}
return f.cache.DelFriendIDs(friendRequest.ToUserID, friendRequest.FromUserID).ExecDel(ctx)
})
}
// 删除好友 外部判断是否好友关系
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
}
return f.cache.DelFriendIDs(append(friendUserIDs, ownerUserID)...).ExecDel(ctx)
}
// 更新好友备注 零值也支持
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
}
return f.cache.DelFriend(ownerUserID, friendUserID).ExecDel(ctx)
}
// 获取ownerUserID的好友列表 无结果不返回错误
func (f *friendDatabase) PageOwnerFriends(ctx context.Context, ownerUserID string, pageNumber, showNumber int32) (friends []*relation.FriendModel, total int64, err error) {
return f.friend.FindOwnerFriends(ctx, ownerUserID, pageNumber, showNumber)
}
// friendUserID在哪些人的好友列表中
func (f *friendDatabase) PageInWhoseFriends(ctx context.Context, friendUserID string, pageNumber, showNumber int32) (friends []*relation.FriendModel, total int64, err error) {
return f.friend.FindInWhoseFriends(ctx, friendUserID, pageNumber, showNumber)
}
// 获取我发出去的好友申请 无结果不返回错误
func (f *friendDatabase) PageFriendRequestFromMe(ctx context.Context, userID string, pageNumber, showNumber int32) (friends []*relation.FriendRequestModel, total int64, err error) {
return f.friendRequest.FindFromUserID(ctx, userID, pageNumber, showNumber)
}
// 获取我收到的的好友申请 无结果不返回错误
func (f *friendDatabase) PageFriendRequestToMe(ctx context.Context, userID string, pageNumber, showNumber int32) (friends []*relation.FriendRequestModel, total int64, err error) {
return f.friendRequest.FindToUserID(ctx, userID, pageNumber, showNumber)
}
// 获取某人指定好友的信息 如果有好友不存在,也返回错误
func (f *friendDatabase) FindFriendsWithError(ctx context.Context, ownerUserID string, friendUserIDs []string) (friends []*relation.FriendModel, err error) {
friends, err = f.friend.FindFriends(ctx, ownerUserID, friendUserIDs)
if err != nil {
return
}
if len(friends) != len(friendUserIDs) {
err = errs.ErrRecordNotFound.Wrap()
}
return
}
func (f *friendDatabase) FindFriendUserIDs(ctx context.Context, ownerUserID string) (friendUserIDs []string, err error) {
return f.cache.GetFriendIDs(ctx, ownerUserID)
}
+421
View File
@@ -0,0 +1,421 @@
package controller
import (
"context"
"fmt"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/constant"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/relation"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
"github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/mongo"
"gorm.io/gorm"
)
type GroupDatabase interface {
// Group
CreateGroup(ctx context.Context, groups []*relationTb.GroupModel, groupMembers []*relationTb.GroupMemberModel) error
TakeGroup(ctx context.Context, groupID string) (group *relationTb.GroupModel, err error)
FindGroup(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error)
SearchGroup(ctx context.Context, keyword string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupModel, error)
UpdateGroup(ctx context.Context, groupID string, data map[string]any) error
DismissGroup(ctx context.Context, groupID string, deleteMember bool) error // 解散群,并删除群成员
GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error)
// GroupMember
TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationTb.GroupMemberModel, err error)
TakeGroupOwner(ctx context.Context, groupID string) (*relationTb.GroupMemberModel, error)
FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) ([]*relationTb.GroupMemberModel, error)
FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error)
FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error)
FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error)
PageGroupRequest(ctx context.Context, groupIDs []string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupRequestModel, error)
//PageGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32, pageNumber, showNumber int32) (uint32, []*relationTb.GroupMemberModel, error)
PageGetJoinGroup(ctx context.Context, userID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationTb.GroupMemberModel, err error)
PageGetGroupMember(ctx context.Context, groupID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationTb.GroupMemberModel, err error)
SearchGroupMember(ctx context.Context, keyword string, groupIDs []string, userIDs []string, roleLevels []int32, pageNumber, showNumber int32) (uint32, []*relationTb.GroupMemberModel, error)
HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationTb.GroupMemberModel) error
DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error
MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationTb.GroupSimpleUserID, error)
MapGroupMemberNum(ctx context.Context, groupIDs []string) (map[string]uint32, error)
TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error // 转让群
UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error
UpdateGroupMembers(ctx context.Context, data []*relationTb.BatchUpdateGroupMember) error
// GroupRequest
CreateGroupRequest(ctx context.Context, requests []*relationTb.GroupRequestModel) error
TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationTb.GroupRequestModel, error)
PageGroupRequestUser(ctx context.Context, userID string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupRequestModel, error)
// SuperGroupModelInterface
FindSuperGroup(ctx context.Context, groupIDs []string) ([]*unRelationTb.SuperGroupModel, error)
FindJoinSuperGroup(ctx context.Context, userID string) ([]string, error)
CreateSuperGroup(ctx context.Context, groupID string, initMemberIDList []string) error
DeleteSuperGroup(ctx context.Context, groupID string) error
DeleteSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error
CreateSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error
}
func NewGroupDatabase(
group relationTb.GroupModelInterface,
member relationTb.GroupMemberModelInterface,
request relationTb.GroupRequestModelInterface,
tx tx.Tx,
ctxTx tx.CtxTx,
superGroup unRelationTb.SuperGroupModelInterface,
cache cache.GroupCache,
) GroupDatabase {
database := &groupDatabase{
groupDB: group,
groupMemberDB: member,
groupRequestDB: request,
tx: tx,
ctxTx: ctxTx,
cache: cache,
mongoDB: superGroup,
}
return database
}
func InitGroupDatabase(db *gorm.DB, rdb redis.UniversalClient, database *mongo.Database) GroupDatabase {
rcOptions := rockscache.NewDefaultOptions()
rcOptions.StrongConsistency = true
rcOptions.RandomExpireAdjustment = 0.2
return NewGroupDatabase(
relation.NewGroupDB(db),
relation.NewGroupMemberDB(db),
relation.NewGroupRequest(db),
tx.NewGorm(db),
tx.NewMongo(database.Client()),
unrelation.NewSuperGroupMongoDriver(database),
cache.NewGroupCacheRedis(rdb, relation.NewGroupDB(db), relation.NewGroupMemberDB(db), relation.NewGroupRequest(db), unrelation.NewSuperGroupMongoDriver(database), rcOptions),
)
}
type groupDatabase struct {
groupDB relationTb.GroupModelInterface
groupMemberDB relationTb.GroupMemberModelInterface
groupRequestDB relationTb.GroupRequestModelInterface
tx tx.Tx
ctxTx tx.CtxTx
cache cache.GroupCache
mongoDB unRelationTb.SuperGroupModelInterface
}
func (g *groupDatabase) GetGroupIDsByGroupType(ctx context.Context, groupType int) (groupIDs []string, err error) {
return g.groupDB.GetGroupIDsByGroupType(ctx, groupType)
}
func (g *groupDatabase) FindGroupMemberUserID(ctx context.Context, groupID string) ([]string, error) {
return g.cache.GetGroupMemberIDs(ctx, groupID)
}
func (g *groupDatabase) FindGroupMemberNum(ctx context.Context, groupID string) (uint32, error) {
num, err := g.cache.GetGroupMemberNum(ctx, groupID)
if err != nil {
return 0, err
}
return uint32(num), nil
}
func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*relationTb.GroupModel, groupMembers []*relationTb.GroupMemberModel) error {
var cache = g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
if len(groups) > 0 {
if err := g.groupDB.NewTx(tx).Create(ctx, groups); err != nil {
return err
}
}
if len(groupMembers) > 0 {
if err := g.groupMemberDB.NewTx(tx).Create(ctx, groupMembers); err != nil {
return err
}
}
createGroupIDs := utils.DistinctAnyGetComparable(groups, func(group *relationTb.GroupModel) string {
return group.GroupID
})
m := make(map[string]struct{})
for _, groupMember := range groupMembers {
if _, ok := m[groupMember.GroupID]; !ok {
m[groupMember.GroupID] = struct{}{}
cache = cache.DelGroupMemberIDs(groupMember.GroupID).DelGroupMembersHash(groupMember.GroupID).DelGroupsMemberNum(groupMember.GroupID)
}
cache = cache.DelJoinedGroupID(groupMember.UserID).DelGroupMembersInfo(groupMember.GroupID, groupMember.UserID)
}
cache = cache.DelGroupsInfo(createGroupIDs...)
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) TakeGroup(ctx context.Context, groupID string) (group *relationTb.GroupModel, err error) {
return g.cache.GetGroupInfo(ctx, groupID)
}
func (g *groupDatabase) FindGroup(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error) {
return g.cache.GetGroupsInfo(ctx, groupIDs)
}
func (g *groupDatabase) SearchGroup(ctx context.Context, keyword string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupModel, error) {
return g.groupDB.Search(ctx, keyword, pageNumber, showNumber)
}
func (g *groupDatabase) UpdateGroup(ctx context.Context, groupID string, data map[string]any) error {
if err := g.groupDB.UpdateMap(ctx, groupID, data); err != nil {
return err
}
return g.cache.DelGroupsInfo(groupID).ExecDel(ctx)
}
func (g *groupDatabase) DismissGroup(ctx context.Context, groupID string, deleteMember bool) error {
cache := g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
if err := g.groupDB.NewTx(tx).UpdateStatus(ctx, groupID, constant.GroupStatusDismissed); err != nil {
return err
}
if deleteMember {
if err := g.groupMemberDB.NewTx(tx).DeleteGroup(ctx, []string{groupID}); err != nil {
return err
}
userIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return err
}
cache = cache.DelJoinedGroupID(userIDs...).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelGroupMembersHash(groupID)
}
cache = cache.DelGroupsInfo(groupID)
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) TakeGroupMember(ctx context.Context, groupID string, userID string) (groupMember *relationTb.GroupMemberModel, err error) {
return g.cache.GetGroupMemberInfo(ctx, groupID, userID)
}
func (g *groupDatabase) TakeGroupOwner(ctx context.Context, groupID string) (*relationTb.GroupMemberModel, error) {
return g.groupMemberDB.TakeOwner(ctx, groupID) // todo cache group owner
}
func (g *groupDatabase) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) {
return g.groupMemberDB.FindUserManagedGroupID(ctx, userID)
}
func (g *groupDatabase) PageGroupRequest(ctx context.Context, groupIDs []string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupRequestModel, error) {
return g.groupRequestDB.PageGroup(ctx, groupIDs, pageNumber, showNumber)
}
func (g *groupDatabase) FindGroupMember(ctx context.Context, groupIDs []string, userIDs []string, roleLevels []int32) (totalGroupMembers []*relationTb.GroupMemberModel, err error) {
if roleLevels == nil {
for _, groupID := range groupIDs {
groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, userIDs)
if err != nil {
return nil, err
}
totalGroupMembers = append(totalGroupMembers, groupMembers...)
}
return totalGroupMembers, nil
}
return g.groupMemberDB.Find(ctx, groupIDs, userIDs, roleLevels)
}
func (g *groupDatabase) PageGetJoinGroup(ctx context.Context, userID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationTb.GroupMemberModel, err error) {
groupIDs, err := g.cache.GetJoinedGroupIDs(ctx, userID)
if err != nil {
return 0, nil, err
}
for _, groupID := range utils.Paginate(groupIDs, int(pageNumber), int(showNumber)) {
groupMembers, err := g.cache.GetGroupMembersInfo(ctx, groupID, []string{userID})
if err != nil {
return 0, nil, err
}
totalGroupMembers = append(totalGroupMembers, groupMembers...)
}
return uint32(len(groupIDs)), totalGroupMembers, nil
}
func (g *groupDatabase) PageGetGroupMember(ctx context.Context, groupID string, pageNumber, showNumber int32) (total uint32, totalGroupMembers []*relationTb.GroupMemberModel, err error) {
groupMemberIDs, err := g.cache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return 0, nil, err
}
pageIDs := utils.Paginate(groupMemberIDs, int(pageNumber), int(showNumber))
if len(pageIDs) == 0 {
return uint32(len(groupMemberIDs)), nil, nil
}
members, err := g.cache.GetGroupMembersInfo(ctx, groupID, pageIDs)
if err != nil {
return 0, nil, err
}
return uint32(len(groupMemberIDs)), members, nil
}
func (g *groupDatabase) SearchGroupMember(ctx context.Context, keyword string, groupIDs []string, userIDs []string, roleLevels []int32, pageNumber, showNumber int32) (uint32, []*relationTb.GroupMemberModel, error) {
return g.groupMemberDB.SearchMember(ctx, keyword, groupIDs, userIDs, roleLevels, pageNumber, showNumber)
}
func (g *groupDatabase) HandlerGroupRequest(ctx context.Context, groupID string, userID string, handledMsg string, handleResult int32, member *relationTb.GroupMemberModel) error {
cache := g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
return err
}
if member != nil {
if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
return err
}
cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID)
}
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error {
if err := g.groupMemberDB.Delete(ctx, groupID, userIDs); err != nil {
return err
}
return g.cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(userIDs...).DelGroupMembersInfo(groupID, userIDs...).ExecDel(ctx)
}
func (g *groupDatabase) MapGroupMemberUserID(ctx context.Context, groupIDs []string) (map[string]*relationTb.GroupSimpleUserID, error) {
return g.cache.GetGroupMemberHashMap(ctx, groupIDs)
}
func (g *groupDatabase) MapGroupMemberNum(ctx context.Context, groupIDs []string) (m map[string]uint32, err error) {
m = make(map[string]uint32)
for _, groupID := range groupIDs {
num, err := g.cache.GetGroupMemberNum(ctx, groupID)
if err != nil {
return nil, err
}
m[groupID] = uint32(num)
}
return m, nil
}
func (g *groupDatabase) TransferGroupOwner(ctx context.Context, groupID string, oldOwnerUserID, newOwnerUserID string, roleLevel int32) error {
if err := g.tx.Transaction(func(tx any) error {
rowsAffected, err := g.groupMemberDB.NewTx(tx).UpdateRoleLevel(ctx, groupID, oldOwnerUserID, roleLevel)
if err != nil {
return err
}
if rowsAffected != 1 {
return utils.Wrap(fmt.Errorf("oldOwnerUserID %s rowsAffected = %d", oldOwnerUserID, rowsAffected), "")
}
rowsAffected, err = g.groupMemberDB.NewTx(tx).UpdateRoleLevel(ctx, groupID, newOwnerUserID, constant.GroupOwner)
if err != nil {
return err
}
if rowsAffected != 1 {
return utils.Wrap(fmt.Errorf("newOwnerUserID %s rowsAffected = %d", newOwnerUserID, rowsAffected), "")
}
return nil
}); err != nil {
return err
}
return g.cache.DelGroupMembersInfo(groupID, oldOwnerUserID, newOwnerUserID).ExecDel(ctx)
}
func (g *groupDatabase) UpdateGroupMember(ctx context.Context, groupID string, userID string, data map[string]any) error {
if err := g.groupMemberDB.Update(ctx, groupID, userID, data); err != nil {
return err
}
return g.cache.DelGroupMembersInfo(groupID, userID).ExecDel(ctx)
}
func (g *groupDatabase) UpdateGroupMembers(ctx context.Context, data []*relationTb.BatchUpdateGroupMember) error {
var cache = g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
for _, item := range data {
if err := g.groupMemberDB.NewTx(tx).Update(ctx, item.GroupID, item.UserID, item.Map); err != nil {
return err
}
cache = cache.DelGroupMembersInfo(item.GroupID, item.UserID)
}
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) CreateGroupRequest(ctx context.Context, requests []*relationTb.GroupRequestModel) error {
return g.tx.Transaction(func(tx any) error {
db := g.groupRequestDB.NewTx(tx)
for _, request := range requests {
if err := db.Delete(ctx, request.GroupID, request.UserID); err != nil {
return err
}
}
return db.Create(ctx, requests)
})
}
func (g *groupDatabase) TakeGroupRequest(ctx context.Context, groupID string, userID string) (*relationTb.GroupRequestModel, error) {
return g.groupRequestDB.Take(ctx, groupID, userID)
}
func (g *groupDatabase) PageGroupRequestUser(ctx context.Context, userID string, pageNumber, showNumber int32) (uint32, []*relationTb.GroupRequestModel, error) {
return g.groupRequestDB.Page(ctx, userID, pageNumber, showNumber)
}
func (g *groupDatabase) FindSuperGroup(ctx context.Context, groupIDs []string) (models []*unRelationTb.SuperGroupModel, err error) {
return g.cache.GetSuperGroupMemberIDs(ctx, groupIDs...)
}
func (g *groupDatabase) FindJoinSuperGroup(ctx context.Context, userID string) ([]string, error) {
return g.cache.GetJoinedSuperGroupIDs(ctx, userID)
}
func (g *groupDatabase) CreateSuperGroup(ctx context.Context, groupID string, initMemberIDs []string) error {
if err := g.mongoDB.CreateSuperGroup(ctx, groupID, initMemberIDs); err != nil {
return err
}
return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(initMemberIDs...).ExecDel(ctx)
}
func (g *groupDatabase) DeleteSuperGroup(ctx context.Context, groupID string) error {
cache := g.cache.NewCache()
if err := g.ctxTx.Transaction(ctx, func(ctx context.Context) error {
if err := g.mongoDB.DeleteSuperGroup(ctx, groupID); err != nil {
return err
}
models, err := g.cache.GetSuperGroupMemberIDs(ctx, groupID)
if err != nil {
return err
}
cache = cache.DelSuperGroupMemberIDs(groupID)
if len(models) > 0 {
cache = cache.DelJoinedSuperGroupIDs(models[0].MemberIDs...)
}
return nil
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) DeleteSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error {
if err := g.mongoDB.RemoverUserFromSuperGroup(ctx, groupID, userIDs); err != nil {
return err
}
return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(userIDs...).ExecDel(ctx)
}
func (g *groupDatabase) CreateSuperGroupMember(ctx context.Context, groupID string, userIDs []string) error {
if err := g.mongoDB.AddUserToSuperGroup(ctx, groupID, userIDs); err != nil {
return err
}
return g.cache.DelSuperGroupMemberIDs(groupID).DelJoinedSuperGroupIDs(userIDs...).ExecDel(ctx)
}
+927
View File
@@ -0,0 +1,927 @@
package controller
import (
"fmt"
"github.com/redis/go-redis/v9"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/convert"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/kafka"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/prome"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"context"
"errors"
pbMsg "github.com/OpenIMSDK/Open-IM-Server/pkg/proto/msg"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/sdkws"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"go.mongodb.org/mongo-driver/mongo"
)
const (
updateKeyMsg = iota
updateKeyRevoke
)
type CommonMsgDatabase interface {
// 批量插入消息
BatchInsertChat2DB(ctx context.Context, conversationID string, msgs []*sdkws.MsgData, currentMaxSeq int64) error
// 撤回消息
RevokeMsg(ctx context.Context, conversationID string, seq int64, revoke *unRelationTb.RevokeModel) error
// mark as read
MarkSingleChatMsgsAsRead(ctx context.Context, userID string, conversationID string, seqs []int64) error
// 刪除redis中消息缓存
DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error
DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64)
// incrSeq然后批量插入缓存
BatchInsertChat2Cache(ctx context.Context, conversationID string, msgs []*sdkws.MsgData) (seq int64, isNewConversation bool, err error)
// 通过seqList获取mongo中写扩散消息
GetMsgBySeqsRange(ctx context.Context, userID string, conversationID string, begin, end, num, userMaxSeq int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error)
// 通过seqList获取大群在 mongo里面的消息
GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (minSeq int64, maxSeq int64, seqMsg []*sdkws.MsgData, err error)
// 删除会话消息重置最小seq, remainTime为消息保留的时间单位秒,超时消息删除, 传0删除所有消息(此方法不删除redis cache)
DeleteConversationMsgsAndSetMinSeq(ctx context.Context, conversationID string, remainTime int64) error
// 用户根据seq删除消息
DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error
// 物理删除消息置空
DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, seqs []int64) error
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
SetConversationUserMinSeqs(ctx context.Context, conversationID string, seqs map[string]int64) (err error)
SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) (err error)
SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error
GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error)
GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error)
UserSetHasReadSeqs(ctx context.Context, userID string, hasReadSeqs map[string]int64) error
GetMongoMaxAndMinSeq(ctx context.Context, conversationID string) (maxSeq, minSeq int64, err error)
GetConversationMinMaxSeqInMongoAndCache(ctx context.Context, conversationID string) (minSeqMongo, maxSeqMongo, minSeqCache, maxSeqCache int64, err error)
SetSendMsgStatus(ctx context.Context, id string, status int32) error
GetSendMsgStatus(ctx context.Context, id string) (int32, error)
// to mq
MsgToMQ(ctx context.Context, key string, msg2mq *sdkws.MsgData) error
MsgToModifyMQ(ctx context.Context, key, conversarionID string, msgs []*sdkws.MsgData) error
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
// modify
JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error)
SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error
SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error)
GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, maxMsgUpdateTime int64) (*pbMsg.ExtendMsg, error)
InsertOrUpdateReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*sdkws.KeyValue) error
GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error)
GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error)
DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error
DeleteReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*sdkws.KeyValue) error
}
func NewCommonMsgDatabase(msgDocModel unRelationTb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
return &commonMsgDatabase{
msgDocDatabase: msgDocModel,
cache: cacheModel,
producer: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.LatestMsgToRedis.Topic),
producerToMongo: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToMongo.Topic),
producerToPush: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToPush.Topic),
producerToModify: kafka.NewKafkaProducer(config.Config.Kafka.Addr, config.Config.Kafka.MsgToModify.Topic),
}
}
func InitCommonMsgDatabase(rdb redis.UniversalClient, database *mongo.Database) CommonMsgDatabase {
cacheModel := cache.NewMsgCacheModel(rdb)
msgDocModel := unrelation.NewMsgMongoDriver(database)
CommonMsgDatabase := NewCommonMsgDatabase(msgDocModel, cacheModel)
return CommonMsgDatabase
}
type commonMsgDatabase struct {
msgDocDatabase unRelationTb.MsgDocModelInterface
extendMsgDatabase unRelationTb.ExtendMsgSetModelInterface
extendMsgSetModel unRelationTb.ExtendMsgSetModel
msg unRelationTb.MsgDocModel
cache cache.MsgModel
producer *kafka.Producer
producerToMongo *kafka.Producer
producerToModify *kafka.Producer
producerToPush *kafka.Producer
}
func (db *commonMsgDatabase) MsgToMQ(ctx context.Context, key string, msg2mq *sdkws.MsgData) error {
_, _, err := db.producer.SendMessage(ctx, key, msg2mq)
return err
}
func (db *commonMsgDatabase) MsgToModifyMQ(ctx context.Context, key, conversationID string, messages []*sdkws.MsgData) error {
if len(messages) > 0 {
_, _, err := db.producerToModify.SendMessage(ctx, key, &pbMsg.MsgDataToModifyByMQ{ConversationID: conversationID, Messages: messages})
return err
}
return nil
}
func (db *commonMsgDatabase) MsgToPushMQ(ctx context.Context, key, conversationID string, msg2mq *sdkws.MsgData) (int32, int64, error) {
partition, offset, err := db.producerToPush.SendMessage(ctx, key, &pbMsg.PushMsgDataToMQ{MsgData: msg2mq, ConversationID: conversationID})
if err != nil {
log.ZError(ctx, "MsgToPushMQ", err, "key", key, "msg2mq", msg2mq)
return 0, 0, err
}
return partition, offset, nil
}
func (db *commonMsgDatabase) MsgToMongoMQ(ctx context.Context, key, conversationID string, messages []*sdkws.MsgData, lastSeq int64) error {
if len(messages) > 0 {
_, _, err := db.producerToMongo.SendMessage(ctx, key, &pbMsg.MsgDataToMongoByMQ{LastSeq: lastSeq, ConversationID: conversationID, MsgData: messages})
return err
}
return nil
}
func (db *commonMsgDatabase) BatchInsertBlock(ctx context.Context, conversationID string, fields []any, key int8, firstSeq int64) error {
if len(fields) == 0 {
return nil
}
num := db.msg.GetSingleGocMsgNum()
//num = 100
for i, field := range fields { // 检查类型
var ok bool
switch key {
case updateKeyMsg:
var msg *unRelationTb.MsgDataModel
msg, ok = field.(*unRelationTb.MsgDataModel)
if msg != nil && msg.Seq != firstSeq+int64(i) {
return errs.ErrInternalServer.Wrap("seq is invalid")
}
case updateKeyRevoke:
_, ok = field.(*unRelationTb.RevokeModel)
default:
return errs.ErrInternalServer.Wrap("key is invalid")
}
if !ok {
return errs.ErrInternalServer.Wrap("field type is invalid")
}
}
// 返回值为true表示数据库存在该文档,false表示数据库不存在该文档
updateMsgModel := func(seq int64, i int) (bool, error) {
var (
res *mongo.UpdateResult
err error
)
docID := db.msg.GetDocID(conversationID, seq)
index := db.msg.GetMsgIndex(seq)
field := fields[i]
switch key {
case updateKeyMsg:
res, err = db.msgDocDatabase.UpdateMsg(ctx, docID, index, "msg", field)
case updateKeyRevoke:
res, err = db.msgDocDatabase.UpdateMsg(ctx, docID, index, "revoke", field)
}
if err != nil {
return false, err
}
return res.MatchedCount > 0, nil
}
tryUpdate := true
for i := 0; i < len(fields); i++ {
seq := firstSeq + int64(i) // 当前seq
if tryUpdate {
matched, err := updateMsgModel(seq, i)
if err != nil {
return err
}
if matched {
continue // 匹配到了,继续下一个(不一定修改)
}
}
doc := unRelationTb.MsgDocModel{
DocID: db.msg.GetDocID(conversationID, seq),
Msg: make([]*unRelationTb.MsgInfoModel, num),
}
var insert int // 插入的数量
for j := i; j < len(fields); j++ {
seq = firstSeq + int64(j)
if db.msg.GetDocID(conversationID, seq) != doc.DocID {
break
}
insert++
switch key {
case updateKeyMsg:
doc.Msg[db.msg.GetMsgIndex(seq)] = &unRelationTb.MsgInfoModel{
Msg: fields[j].(*unRelationTb.MsgDataModel),
}
case updateKeyRevoke:
doc.Msg[db.msg.GetMsgIndex(seq)] = &unRelationTb.MsgInfoModel{
Revoke: fields[j].(*unRelationTb.RevokeModel),
}
}
}
for i, model := range doc.Msg {
if model == nil {
model = &unRelationTb.MsgInfoModel{}
doc.Msg[i] = model
}
if model.DelList == nil {
doc.Msg[i].DelList = []string{}
}
}
if err := db.msgDocDatabase.Create(ctx, &doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
i-- // 存在并发,重试当前数据
tryUpdate = true // 以修改模式
continue
}
return err
}
tryUpdate = false // 当前以插入成功,下一块优先插入模式
i += insert - 1 // 跳过已插入的数据
}
return nil
}
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")
}
msgs := make([]any, len(msgList))
for i, msg := range msgList {
if msg == nil {
continue
}
var offlinePushModel *unRelationTb.OfflinePushModel
if msg.OfflinePushInfo != nil {
offlinePushModel = &unRelationTb.OfflinePushModel{
Title: msg.OfflinePushInfo.Title,
Desc: msg.OfflinePushInfo.Desc,
Ex: msg.OfflinePushInfo.Ex,
IOSPushSound: msg.OfflinePushInfo.IOSPushSound,
IOSBadgeCount: msg.OfflinePushInfo.IOSBadgeCount,
}
}
msgs[i] = &unRelationTb.MsgDataModel{
SendID: msg.SendID,
RecvID: msg.RecvID,
GroupID: msg.GroupID,
ClientMsgID: msg.ClientMsgID,
ServerMsgID: msg.ServerMsgID,
SenderPlatformID: msg.SenderPlatformID,
SenderNickname: msg.SenderNickname,
SenderFaceURL: msg.SenderFaceURL,
SessionType: msg.SessionType,
MsgFrom: msg.MsgFrom,
ContentType: msg.ContentType,
Content: string(msg.Content),
Seq: msg.Seq,
SendTime: msg.SendTime,
CreateTime: msg.CreateTime,
Status: msg.Status,
Options: msg.Options,
OfflinePush: offlinePushModel,
AtUserIDList: msg.AtUserIDList,
AttachedInfo: msg.AttachedInfo,
Ex: msg.Ex,
}
}
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 {
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) {
var indexes []int64
for _, seq := range seqs {
indexes = append(indexes, db.msg.GetMsgIndex(seq))
}
log.ZDebug(ctx, "MarkSingleChatMsgsAsRead", "userID", userID, "docID", docID, "indexes", indexes)
if err := db.msgDocDatabase.MarkSingleChatMsgsAsRead(ctx, userID, docID, indexes); err != nil {
log.ZError(ctx, "MarkSingleChatMsgsAsRead", err, "userID", userID, "docID", docID, "indexes", indexes)
return err
}
}
return nil
}
func (db *commonMsgDatabase) DeleteMessagesFromCache(ctx context.Context, conversationID string, seqs []int64) error {
return db.cache.DeleteMessages(ctx, conversationID, seqs)
}
func (db *commonMsgDatabase) DelUserDeleteMsgsList(ctx context.Context, conversationID string, seqs []int64) {
db.cache.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)
if err != nil && errs.Unwrap(err) != redis.Nil {
prome.Inc(prome.SeqGetFailedCounter)
return 0, false, err
}
prome.Inc(prome.SeqGetSuccessCounter)
lenList := len(msgs)
if int64(lenList) > db.msg.GetSingleGocMsgNum() {
return 0, false, errors.New("too large")
}
if lenList < 1 {
return 0, false, errors.New("too short as 0")
}
if errs.Unwrap(err) == redis.Nil {
isNew = true
}
lastMaxSeq := currentMaxSeq
userSeqMap := make(map[string]int64)
for _, m := range msgs {
currentMaxSeq++
m.Seq = currentMaxSeq
userSeqMap[m.SendID] = m.Seq
}
failedNum, err := db.cache.SetMessageToCache(ctx, conversationID, msgs)
if err != nil {
prome.Add(prome.MsgInsertRedisFailedCounter, failedNum)
log.ZError(ctx, "setMessageToCache error", err, "len", len(msgs), "conversationID", conversationID)
} else {
prome.Inc(prome.MsgInsertRedisSuccessCounter)
}
err = db.cache.SetMaxSeq(ctx, conversationID, currentMaxSeq)
if err != nil {
prome.Inc(prome.SeqSetFailedCounter)
} else {
prome.Inc(prome.SeqSetSuccessCounter)
}
err2 := db.cache.SetHasReadSeqs(ctx, conversationID, userSeqMap)
if err != nil {
log.ZError(ctx, "SetHasReadSeqs error", err2, "userSeqMap", userSeqMap, "conversationID", conversationID)
prome.Inc(prome.SeqSetFailedCounter)
} else {
prome.Inc(prome.SeqSetSuccessCounter)
}
return lastMaxSeq, isNew, utils.Wrap(err, "")
}
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) {
//log.ZDebug(ctx, "getMsgBySeqs", "docID", docID, "seqs", seqs)
msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, seqs)
if err != nil {
return nil, err
}
for _, msg := range msgs {
totalMsgs = append(totalMsgs, convert.MsgDB2Pb(msg.Msg))
}
}
return totalMsgs, nil
}
// func (db *commonMsgDatabase) refetchDelSeqsMsgs(ctx context.Context, conversationID string, delNums, rangeBegin, begin int64) (seqMsgs []*unRelationTb.MsgDataModel, err error) {
// var reFetchSeqs []int64
// if delNums > 0 {
// newBeginSeq := rangeBegin - delNums
// if newBeginSeq >= begin {
// newEndSeq := rangeBegin - 1
// for i := newBeginSeq; i <= newEndSeq; i++ {
// reFetchSeqs = append(reFetchSeqs, i)
// }
// }
// }
// if len(reFetchSeqs) == 0 {
// return
// }
// if len(reFetchSeqs) > 0 {
// m := db.msg.GetDocIDSeqsMap(conversationID, reFetchSeqs)
// for docID, seqs := range m {
// msgs, _, err := db.findMsgInfoBySeq(ctx, docID, seqs)
// if err != nil {
// return nil, err
// }
// for _, msg := range msgs {
// if msg.Status != constant.MsgDeleted {
// seqMsgs = append(seqMsgs, msg)
// }
// }
// }
// }
// if len(seqMsgs) < int(delNums) {
// seqMsgs2, err := db.refetchDelSeqsMsgs(ctx, conversationID, delNums-int64(len(seqMsgs)), rangeBegin-1, begin)
// if err != nil {
// return seqMsgs, err
// }
// seqMsgs = append(seqMsgs, seqMsgs2...)
// }
// return seqMsgs, nil
// }
func (db *commonMsgDatabase) findMsgInfoBySeq(ctx context.Context, userID, docID string, seqs []int64) (totalMsgs []*unRelationTb.MsgInfoModel, err error) {
msgs, err := db.msgDocDatabase.GetMsgBySeqIndexIn1Doc(ctx, userID, docID, seqs)
for _, msg := range msgs {
if msg.IsRead {
msg.Msg.IsRead = true
}
}
return msgs, err
}
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) {
log.ZDebug(ctx, "getMsgBySeqsRange", "docID", docID, "seqs", seqs)
msgs, err := db.findMsgInfoBySeq(ctx, userID, docID, seqs)
if err != nil {
return nil, err
}
for _, msg := range msgs {
if msg.IsRead {
msg.Msg.IsRead = true
}
seqMsgs = append(seqMsgs, convert.MsgDB2Pb(msg.Msg))
}
}
return seqMsgs, nil
}
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)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
minSeq, err := db.cache.GetMinSeq(ctx, conversationID)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
if userMinSeq > minSeq {
minSeq = userMinSeq
}
if minSeq > end {
log.ZInfo(ctx, "minSeq > end", "minSeq", minSeq, "end", end)
return 0, 0, nil, nil
}
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
log.ZDebug(ctx, "GetMsgBySeqsRange", "userMinSeq", userMinSeq, "conMinSeq", minSeq, "conMaxSeq", maxSeq, "userMaxSeq", userMaxSeq)
if userMaxSeq != 0 {
if userMaxSeq < maxSeq {
maxSeq = userMaxSeq
}
}
if begin < minSeq {
begin = minSeq
}
if end > maxSeq {
end = maxSeq
}
if end < begin {
return 0, 0, nil, errs.ErrArgs.Wrap("seq end < begin")
}
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)
if err != nil {
if err != redis.Nil {
prome.Add(prome.MsgPullFromRedisFailedCounter, len(failedSeqs))
log.ZError(ctx, "get message from redis exception", err, "conversationID", conversationID, "seqs", seqs)
}
}
var successMsgs []*sdkws.MsgData
if len(cachedMsgs) > 0 {
delSeqs, err := db.cache.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...) {
successMsgs = append(successMsgs, msg)
} else {
cacheDelNum += 1
}
}
log.ZDebug(ctx, "get delSeqs from redis", "delSeqs", delSeqs, "userID", userID, "conversationID", conversationID, "cacheDelNum", cacheDelNum)
var reGetSeqsCache []int64
for i := 1; i <= cacheDelNum; {
newSeq := newBegin - int64(i)
if newSeq >= begin {
if !utils.Contain(newSeq, delSeqs...) {
log.ZDebug(ctx, "seq del in cache, a new seq in range append", "new seq", newSeq)
reGetSeqsCache = append(reGetSeqsCache, newSeq)
i++
}
} else {
break
}
}
if len(reGetSeqsCache) > 0 {
log.ZDebug(ctx, "reGetSeqsCache", "reGetSeqsCache", reGetSeqsCache)
cachedMsgs, failedSeqs2, err := db.cache.GetMessagesBySeq(ctx, conversationID, reGetSeqsCache)
if err != nil {
if err != redis.Nil {
prome.Add(prome.MsgPullFromRedisFailedCounter, len(failedSeqs2))
log.ZError(ctx, "get message from redis exception", err, "conversationID", conversationID, "seqs", reGetSeqsCache)
}
}
failedSeqs = append(failedSeqs, failedSeqs2...)
successMsgs = append(successMsgs, cachedMsgs...)
}
}
log.ZDebug(ctx, "get msgs from cache", "successMsgs", successMsgs)
if len(failedSeqs) != 0 {
log.ZDebug(ctx, "msgs not exist in redis", "seqs", failedSeqs)
}
// get from cache or db
prome.Add(prome.MsgPullFromRedisSuccessCounter, len(successMsgs))
if len(failedSeqs) > 0 {
mongoMsgs, err := db.getMsgBySeqsRange(ctx, userID, conversationID, failedSeqs, begin, end)
if err != nil {
prome.Add(prome.MsgPullFromMongoFailedCounter, len(failedSeqs))
return 0, 0, nil, err
}
prome.Add(prome.MsgPullFromMongoSuccessCounter, len(mongoMsgs))
successMsgs = append(successMsgs, mongoMsgs...)
}
return minSeq, maxSeq, successMsgs, nil
}
func (db *commonMsgDatabase) GetMsgBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) (int64, int64, []*sdkws.MsgData, error) {
userMinSeq, err := db.cache.GetConversationUserMinSeq(ctx, conversationID, userID)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
minSeq, err := db.cache.GetMinSeq(ctx, conversationID)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
if err != nil && errs.Unwrap(err) != redis.Nil {
return 0, 0, nil, err
}
if userMinSeq < minSeq {
minSeq = userMinSeq
}
var newSeqs []int64
for _, seq := range seqs {
if seq >= minSeq && seq <= maxSeq {
newSeqs = append(newSeqs, seq)
}
}
successMsgs, failedSeqs, err := db.cache.GetMessagesBySeq(ctx, conversationID, newSeqs)
if err != nil {
if err != redis.Nil {
prome.Add(prome.MsgPullFromRedisFailedCounter, len(failedSeqs))
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)
prome.Add(prome.MsgPullFromRedisSuccessCounter, len(successMsgs))
if len(failedSeqs) > 0 {
mongoMsgs, err := db.getMsgBySeqs(ctx, userID, conversationID, failedSeqs)
if err != nil {
prome.Add(prome.MsgPullFromMongoFailedCounter, len(failedSeqs))
return 0, 0, nil, err
}
prome.Add(prome.MsgPullFromMongoSuccessCounter, len(mongoMsgs))
successMsgs = append(successMsgs, mongoMsgs...)
}
return minSeq, maxSeq, successMsgs, nil
}
func (db *commonMsgDatabase) DeleteConversationMsgsAndSetMinSeq(ctx context.Context, conversationID string, remainTime int64) error {
var delStruct delMsgRecursionStruct
var skip int64
minSeq, err := db.deleteMsgRecursion(ctx, conversationID, skip, &delStruct, remainTime)
if err != nil {
return err
}
log.ZInfo(ctx, "DeleteConversationMsgsAndSetMinSeq", "conversationID", conversationID, "minSeq", minSeq)
if minSeq == 0 {
return nil
}
if remainTime == 0 {
err = db.cache.CleanUpOneConversationAllMsg(ctx, conversationID)
if err != nil {
log.ZWarn(ctx, "CleanUpOneUserAllMsg", err, "conversationID", conversationID)
}
}
return db.cache.SetMinSeq(ctx, conversationID, minSeq)
}
// this is struct for recursion
type delMsgRecursionStruct struct {
minSeq int64
delDocIDs []string
}
func (d *delMsgRecursionStruct) getSetMinSeq() int64 {
return d.minSeq
}
// index 0....19(del) 20...69
// seq 70
// set minSeq 21
// recursion 删除list并且返回设置的最小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)
if err != nil || msgDocModel.DocID == "" {
if err != nil {
if err == unrelation.ErrMsgListNotExist {
log.ZDebug(ctx, "deleteMsgRecursion ErrMsgListNotExist", "conversationID", conversationID, "index:", index)
} else {
log.ZError(ctx, "deleteMsgRecursion GetUserMsgListByIndex failed", err, "conversationID", conversationID, "index", index)
}
}
// 获取报错,或者获取不到了,物理删除并且返回seq delMongoMsgsPhysical(delStruct.delDocIDList), 结束递归
err = db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs)
if err != nil {
return 0, err
}
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() {
log.ZWarn(ctx, "msgs too large", nil, "lenth", len(msgDocModel.Msg), "docID:", msgDocModel.DocID)
}
if msgDocModel.IsFull() && msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.SendTime+(remainTime*1000) < utils.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
} else {
var hasMarkDelFlag bool
var delMsgIndexs []int
for i, MsgInfoModel := range msgDocModel.Msg {
if MsgInfoModel != nil && MsgInfoModel.Msg != nil {
if utils.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) {
delMsgIndexs = append(delMsgIndexs, i)
hasMarkDelFlag = true
} else {
// 到本条消息不需要删除, minSeq置为这条消息的seq
if len(delStruct.delDocIDs) > 0 {
log.ZDebug(ctx, "delete docs", "delDocIDs", delStruct.delDocIDs)
}
if err := db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs); err != nil {
return 0, err
}
if hasMarkDelFlag {
log.ZDebug(ctx, "delete msg by index", "delMsgIndexs", delMsgIndexs, "docID", msgDocModel.DocID)
// mark del all delMsgIndexs
if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil {
return delStruct.getSetMinSeq(), err
}
}
return MsgInfoModel.Msg.Seq, nil
}
}
}
}
// 继续递归 index+1
seq, err := db.deleteMsgRecursion(ctx, conversationID, index+1, delStruct, remainTime)
return seq, err
}
func (db *commonMsgDatabase) DeleteMsgsPhysicalBySeqs(ctx context.Context, conversationID string, allSeqs []int64) error {
if err := db.cache.DeleteMessages(ctx, conversationID, allSeqs); err != nil {
return err
}
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, allSeqs) {
var indexes []int
for _, seq := range seqs {
indexes = append(indexes, int(db.msg.GetMsgIndex(seq)))
}
if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, docID, indexes); err != nil {
return err
}
}
return nil
}
func (db *commonMsgDatabase) DeleteUserMsgsBySeqs(ctx context.Context, userID string, conversationID string, seqs []int64) error {
cachedMsgs, _, err := db.cache.GetMessagesBySeq(ctx, conversationID, seqs)
if err != nil && errs.Unwrap(err) != redis.Nil {
log.ZWarn(ctx, "DeleteUserMsgsBySeqs", err, "conversationID", conversationID, "seqs", seqs)
return err
}
if len(cachedMsgs) > 0 {
var cacheSeqs []int64
for _, msg := range cachedMsgs {
cacheSeqs = append(cacheSeqs, msg.Seq)
}
if err := db.cache.UserDeleteMsgs(ctx, conversationID, cacheSeqs, userID); err != nil {
return err
}
}
for docID, seqs := range db.msg.GetDocIDSeqsMap(conversationID, seqs) {
for _, seq := range seqs {
if _, err := db.msgDocDatabase.PushUnique(ctx, docID, db.msg.GetMsgIndex(seq), "del_list", []string{userID}); err != nil {
return err
}
}
}
return nil
}
func (db *commonMsgDatabase) DeleteMsgsBySeqs(ctx context.Context, conversationID string, seqs []int64) error {
return nil
}
func (db *commonMsgDatabase) CleanUpUserConversationsMsgs(ctx context.Context, user string, conversationIDs []string) {
for _, conversationID := range conversationIDs {
maxSeq, err := db.cache.GetMaxSeq(ctx, conversationID)
if err != nil {
if err == redis.Nil {
log.ZInfo(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 {
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)
}
func (db *commonMsgDatabase) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
return db.cache.GetMaxSeqs(ctx, conversationIDs)
}
func (db *commonMsgDatabase) GetMaxSeq(ctx context.Context, conversationID string) (int64, error) {
return db.cache.GetMaxSeq(ctx, conversationID)
}
func (db *commonMsgDatabase) SetMinSeq(ctx context.Context, conversationID string, minSeq int64) error {
return db.cache.SetMinSeq(ctx, conversationID, minSeq)
}
func (db *commonMsgDatabase) SetMinSeqs(ctx context.Context, seqs map[string]int64) error {
return db.cache.SetMinSeqs(ctx, seqs)
}
func (db *commonMsgDatabase) GetMinSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
return db.cache.GetMinSeqs(ctx, conversationIDs)
}
func (db *commonMsgDatabase) GetMinSeq(ctx context.Context, conversationID string) (int64, error) {
return db.cache.GetMinSeq(ctx, conversationID)
}
func (db *commonMsgDatabase) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
return db.cache.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)
}
func (db *commonMsgDatabase) SetConversationUserMinSeq(ctx context.Context, conversationID string, userID string, minSeq int64) error {
return db.cache.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)
}
func (db *commonMsgDatabase) SetUserConversationsMinSeqs(ctx context.Context, userID string, seqs map[string]int64) error {
return db.cache.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)
}
func (db *commonMsgDatabase) SetHasReadSeq(ctx context.Context, userID string, conversationID string, hasReadSeq int64) error {
return db.cache.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)
}
func (db *commonMsgDatabase) GetHasReadSeq(ctx context.Context, userID string, conversationID string) (int64, error) {
return db.cache.GetHasReadSeq(ctx, userID, conversationID)
}
func (db *commonMsgDatabase) SetSendMsgStatus(ctx context.Context, id string, status int32) error {
return db.cache.SetSendMsgStatus(ctx, id, status)
}
func (db *commonMsgDatabase) GetSendMsgStatus(ctx context.Context, id string) (int32, error) {
return db.cache.GetSendMsgStatus(ctx, id)
}
func (db *commonMsgDatabase) GetConversationMinMaxSeqInMongoAndCache(ctx context.Context, conversationID string) (minSeqMongo, maxSeqMongo, minSeqCache, maxSeqCache int64, err error) {
minSeqMongo, maxSeqMongo, err = db.GetMinMaxSeqMongo(ctx, conversationID)
if err != nil {
return
}
minSeqCache, err = db.cache.GetMinSeq(ctx, conversationID)
if err != nil {
return
}
maxSeqCache, err = db.cache.GetMaxSeq(ctx, conversationID)
if err != nil {
return
}
return
}
func (db *commonMsgDatabase) GetMongoMaxAndMinSeq(ctx context.Context, conversationID string) (maxSeq, minSeq int64, err error) {
return db.GetMinMaxSeqMongo(ctx, conversationID)
}
func (db *commonMsgDatabase) GetMinMaxSeqMongo(ctx context.Context, conversationID string) (minSeqMongo, maxSeqMongo int64, err error) {
oldestMsgMongo, err := db.msgDocDatabase.GetOldestMsg(ctx, conversationID)
if err != nil {
return
}
minSeqMongo = oldestMsgMongo.Msg.Seq
newestMsgMongo, err := db.msgDocDatabase.GetNewestMsg(ctx, conversationID)
if err != nil {
return
}
maxSeqMongo = newestMsgMongo.Msg.Seq
return
}
func (db *commonMsgDatabase) JudgeMessageReactionExist(ctx context.Context, clientMsgID string, sessionType int32) (bool, error) {
return db.cache.JudgeMessageReactionExist(ctx, clientMsgID, sessionType)
}
func (db *commonMsgDatabase) SetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey, value string) error {
return db.cache.SetMessageTypeKeyValue(ctx, clientMsgID, sessionType, typeKey, value)
}
func (db *commonMsgDatabase) SetMessageReactionExpire(ctx context.Context, clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) {
return db.cache.SetMessageReactionExpire(ctx, clientMsgID, sessionType, expiration)
}
func (db *commonMsgDatabase) GetMessageTypeKeyValue(ctx context.Context, clientMsgID string, sessionType int32, typeKey string) (string, error) {
return db.cache.GetMessageTypeKeyValue(ctx, clientMsgID, sessionType, typeKey)
}
func (db *commonMsgDatabase) GetOneMessageAllReactionList(ctx context.Context, clientMsgID string, sessionType int32) (map[string]string, error) {
return db.cache.GetOneMessageAllReactionList(ctx, clientMsgID, sessionType)
}
func (db *commonMsgDatabase) DeleteOneMessageKey(ctx context.Context, clientMsgID string, sessionType int32, subKey string) error {
return db.cache.DeleteOneMessageKey(ctx, clientMsgID, sessionType, subKey)
}
func (db *commonMsgDatabase) InsertOrUpdateReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensions map[string]*sdkws.KeyValue) error {
return db.extendMsgDatabase.InsertOrUpdateReactionExtendMsgSet(ctx, conversationID, sessionType, clientMsgID, msgFirstModifyTime, db.extendMsgSetModel.Pb2Model(reactionExtensions))
}
func (db *commonMsgDatabase) GetExtendMsg(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, maxMsgUpdateTime int64) (*pbMsg.ExtendMsg, error) {
extendMsgSet, err := db.extendMsgDatabase.GetExtendMsgSet(ctx, conversationID, sessionType, maxMsgUpdateTime)
if err != nil {
return nil, err
}
extendMsg, ok := extendMsgSet.ExtendMsgs[clientMsgID]
if !ok {
return nil, errs.ErrRecordNotFound.Wrap(fmt.Sprintf("cant find client msg id: %s", clientMsgID))
}
reactionExtensionList := make(map[string]*pbMsg.KeyValueResp)
for key, model := range extendMsg.ReactionExtensionList {
reactionExtensionList[key] = &pbMsg.KeyValueResp{
KeyValue: &sdkws.KeyValue{
TypeKey: model.TypeKey,
Value: model.Value,
LatestUpdateTime: model.LatestUpdateTime,
},
}
}
return &pbMsg.ExtendMsg{
ReactionExtensions: reactionExtensionList,
ClientMsgID: extendMsg.ClientMsgID,
MsgFirstModifyTime: extendMsg.MsgFirstModifyTime,
AttachedInfo: extendMsg.AttachedInfo,
Ex: extendMsg.Ex,
}, nil
}
func (db *commonMsgDatabase) DeleteReactionExtendMsgSet(ctx context.Context, conversationID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensions map[string]*sdkws.KeyValue) error {
return db.extendMsgDatabase.DeleteReactionExtendMsgSet(ctx, conversationID, sessionType, clientMsgID, msgFirstModifyTime, db.extendMsgSetModel.Pb2Model(reactionExtensions))
}
+251
View File
@@ -0,0 +1,251 @@
package controller
import (
"context"
"fmt"
"math/rand"
"strconv"
"sync"
"testing"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation"
"go.mongodb.org/mongo-driver/bson"
)
func Test_BatchInsertChat2DB(t *testing.T) {
config.Config.Mongo.Address = []string{"192.168.44.128:37017"}
config.Config.Mongo.Timeout = 60
config.Config.Mongo.Database = "openIM"
config.Config.Mongo.Source = "admin"
config.Config.Mongo.Username = "root"
config.Config.Mongo.Password = "openIM123"
config.Config.Mongo.MaxPoolSize = 100
config.Config.RetainChatRecords = 3650
config.Config.ChatRecordsClearTime = "0 2 * * 3"
mongo, err := unrelation.NewMongo()
if err != nil {
t.Fatal(err)
}
err = mongo.GetDatabase().Client().Ping(context.Background(), nil)
if err != nil {
panic(err)
}
db := &commonMsgDatabase{
msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()),
}
//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().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 {
config.Config.Mongo.Address = []string{"192.168.44.128:37017"}
config.Config.Mongo.Timeout = 60
config.Config.Mongo.Database = "openIM"
config.Config.Mongo.Source = "admin"
config.Config.Mongo.Username = "root"
config.Config.Mongo.Password = "openIM123"
config.Config.Mongo.MaxPoolSize = 100
config.Config.RetainChatRecords = 3650
config.Config.ChatRecordsClearTime = "0 2 * * 3"
mongo, err := unrelation.NewMongo()
if err != nil {
panic(err)
}
err = mongo.GetDatabase().Client().Ping(context.Background(), nil)
if err != nil {
panic(err)
}
return &commonMsgDatabase{
msgDocDatabase: unrelation.NewMsgMongoDriver(mongo.GetDatabase()),
}
}
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); 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 Test_Delete1(t *testing.T) {
// config.Config.Mongo.DBAddress = []string{"192.168.44.128:37017"}
// config.Config.Mongo.DBTimeout = 60
// config.Config.Mongo.DBDatabase = "openIM"
// config.Config.Mongo.DBSource = "admin"
// config.Config.Mongo.DBUserName = "root"
// config.Config.Mongo.DBPassword = "openIM123"
// config.Config.Mongo.DBMaxPoolSize = 100
// config.Config.Mongo.DBRetainChatRecords = 3650
// config.Config.Mongo.ChatRecordsClearTime = "0 2 * * 3"
//
// mongo, err := unrelation.NewMongo()
// if err != nil {
// panic(err)
// }
// err = mongo.GetDatabase().Client().Ping(context.Background(), nil)
// if err != nil {
// panic(err)
// }
//
// c := mongo.GetClient().Database("openIM").Collection("msg")
//
// var o unRelationTb.MsgDocModel
//
// err = c.FindOne(context.Background(), bson.M{"doc_id": "test:0"}).Decode(&o)
// if err != nil {
// panic(err)
// }
//
// for i, model := range o.Msg {
// fmt.Println(i, model == nil)
// }
//
//}
+23
View File
@@ -0,0 +1,23 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
)
type PushDatabase interface {
DelFcmToken(ctx context.Context, userID string, platformID int) error
}
type pushDataBase struct {
cache cache.MsgModel
}
func NewPushDatabase(cache cache.MsgModel) PushDatabase {
return &pushDataBase{cache: cache}
}
func (p *pushDataBase) DelFcmToken(ctx context.Context, userID string, platformID int) error {
return p.cache.DelFcmToken(ctx, userID, platformID)
}
+539
View File
@@ -0,0 +1,539 @@
package controller
import "C"
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/obj"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/log"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/third"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/google/uuid"
"io"
"net/url"
"path"
"strconv"
"time"
)
const (
hashPrefix = "hash"
tempPrefix = "temp"
fragmentPrefix = "fragment_"
urlsName = "urls.json"
)
type S3Database interface {
ApplyPut(ctx context.Context, req *third.ApplyPutReq) (*third.ApplyPutResp, error)
GetPut(ctx context.Context, req *third.GetPutReq) (*third.GetPutResp, error)
ConfirmPut(ctx context.Context, req *third.ConfirmPutReq) (*third.ConfirmPutResp, error)
GetUrl(ctx context.Context, req *third.GetUrlReq) (*third.GetUrlResp, error)
GetHashInfo(ctx context.Context, req *third.GetHashInfoReq) (*third.GetHashInfoResp, error)
CleanExpirationObject(ctx context.Context, t time.Time)
}
func NewS3Database(obj obj.Interface, hash relation.ObjectHashModelInterface, info relation.ObjectInfoModelInterface, put relation.ObjectPutModelInterface, url *url.URL) S3Database {
return &s3Database{
url: url,
obj: obj,
hash: hash,
info: info,
put: put,
}
}
type s3Database struct {
url *url.URL
obj obj.Interface
hash relation.ObjectHashModelInterface
info relation.ObjectInfoModelInterface
put relation.ObjectPutModelInterface
}
// today 今天的日期
func (c *s3Database) today() string {
return time.Now().Format("20060102")
}
// fragmentName 根据序号生成文件名
func (c *s3Database) fragmentName(index int) string {
return fragmentPrefix + strconv.Itoa(index+1)
}
// getFragmentNum 获取分片大小和分片数量
func (c *s3Database) getFragmentNum(fragmentSize int64, objectSize int64) (int64, int) {
if size := c.obj.MinFragmentSize(); fragmentSize < size {
fragmentSize = size
}
if fragmentSize <= 0 || objectSize <= fragmentSize {
return objectSize, 1
} else {
num := int(objectSize / fragmentSize)
if objectSize%fragmentSize > 0 {
num++
}
if n := c.obj.MaxFragmentNum(); num > n {
num = n
}
return fragmentSize, num
}
}
func (c *s3Database) CheckHash(hash string) error {
val, err := hex.DecodeString(hash)
if err != nil {
return err
}
if len(val) != md5.Size {
return errs.ErrArgs.Wrap("invalid hash")
}
return nil
}
func (c *s3Database) urlName(name string) string {
u := url.URL{
Scheme: c.url.Scheme,
Opaque: c.url.Opaque,
User: c.url.User,
Host: c.url.Host,
Path: c.url.Path,
RawPath: c.url.RawPath,
OmitHost: c.url.OmitHost,
ForceQuery: c.url.ForceQuery,
RawQuery: c.url.RawQuery,
Fragment: c.url.Fragment,
RawFragment: c.url.RawFragment,
}
v := make(url.Values, 1)
v.Set("name", name)
u.RawQuery = v.Encode()
return u.String()
}
func (c *s3Database) UUID() string {
return uuid.New().String()
}
func (c *s3Database) HashName(hash string) string {
return path.Join(hashPrefix, hash+"_"+c.today()+"_"+c.UUID())
}
func (c *s3Database) isNotFound(err error) bool {
return relation.IsNotFound(err)
}
func (c *s3Database) ApplyPut(ctx context.Context, req *third.ApplyPutReq) (*third.ApplyPutResp, error) {
if err := c.CheckHash(req.Hash); err != nil {
return nil, err
}
if err := c.obj.CheckName(req.Name); err != nil {
return nil, err
}
if req.ValidTime != 0 && req.ValidTime <= time.Now().UnixMilli() {
return nil, errors.New("invalid ValidTime")
}
var expirationTime *time.Time
if req.ValidTime != 0 {
expirationTime = utils.ToPtr(time.UnixMilli(req.ValidTime))
}
if hash, err := c.hash.Take(ctx, req.Hash, c.obj.Name()); err == nil {
o := relation.ObjectInfoModel{
Name: req.Name,
Hash: hash.Hash,
ValidTime: expirationTime,
ContentType: req.ContentType,
CreateTime: time.Now(),
}
if err := c.info.SetObject(ctx, &o); err != nil {
return nil, err
}
return &third.ApplyPutResp{Url: c.urlName(o.Name)}, nil // 服务器已存在
} else if !c.isNotFound(err) {
return nil, err
}
// 新上传
var fragmentNum int
const effective = time.Hour * 24 * 2
req.FragmentSize, fragmentNum = c.getFragmentNum(req.FragmentSize, req.Size)
put := relation.ObjectPutModel{
PutID: req.PutID,
Hash: req.Hash,
Name: req.Name,
ObjectSize: req.Size,
ContentType: req.ContentType,
FragmentSize: req.FragmentSize,
ValidTime: expirationTime,
EffectiveTime: time.Now().Add(effective),
}
if put.PutID == "" {
put.PutID = c.UUID()
}
if v, err := c.put.Take(ctx, put.PutID); err == nil {
now := time.Now().UnixMilli()
if v.EffectiveTime.UnixMilli() <= now {
if err := c.put.DelPut(ctx, []string{v.PutID}); err != nil {
return nil, err
}
} else {
return nil, errs.ErrDuplicateKey.Wrap(fmt.Sprintf("duplicate put id %s", put.PutID))
}
} else if !c.isNotFound(err) {
return nil, err
}
put.Path = path.Join(tempPrefix, c.today(), req.Hash, put.PutID)
putURLs := make([]string, 0, fragmentNum)
for i := 0; i < fragmentNum; i++ {
url, err := c.obj.PresignedPutURL(ctx, &obj.ApplyPutArgs{
Bucket: c.obj.TempBucket(),
Name: path.Join(put.Path, c.fragmentName(i)),
Effective: effective,
MaxObjectSize: req.FragmentSize,
})
if err != nil {
return nil, err
}
putURLs = append(putURLs, url)
}
urlsJsonData, err := json.Marshal(putURLs)
if err != nil {
return nil, err
}
t := md5.Sum(urlsJsonData)
put.PutURLsHash = hex.EncodeToString(t[:])
_, err = c.obj.PutObject(ctx, &obj.BucketObject{Bucket: c.obj.TempBucket(), Name: path.Join(put.Path, urlsName)}, bytes.NewReader(urlsJsonData), int64(len(urlsJsonData)))
if err != nil {
return nil, err
}
put.CreateTime = time.Now()
if err := c.put.Create(ctx, []*relation.ObjectPutModel{&put}); err != nil {
return nil, err
}
return &third.ApplyPutResp{
PutID: put.PutID,
FragmentSize: put.FragmentSize,
PutURLs: putURLs,
ValidTime: put.EffectiveTime.UnixMilli(),
}, nil
}
func (c *s3Database) GetPut(ctx context.Context, req *third.GetPutReq) (*third.GetPutResp, error) {
up, err := c.put.Take(ctx, req.PutID)
if err != nil {
return nil, err
}
reader, err := c.obj.GetObject(ctx, &obj.BucketObject{Bucket: c.obj.TempBucket(), Name: path.Join(up.Path, urlsName)})
if err != nil {
return nil, err
}
urlsData, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
t := md5.Sum(urlsData)
if h := hex.EncodeToString(t[:]); h != up.PutURLsHash {
return nil, fmt.Errorf("invalid put urls hash %s %s", h, up.PutURLsHash)
}
var urls []string
if err := json.Unmarshal(urlsData, &urls); err != nil {
return nil, err
}
_, fragmentNum := c.getFragmentNum(up.FragmentSize, up.ObjectSize)
if len(urls) != fragmentNum {
return nil, fmt.Errorf("invalid urls length %d fragment %d", len(urls), fragmentNum)
}
fragments := make([]*third.GetPutFragment, fragmentNum)
for i := 0; i < fragmentNum; i++ {
name := path.Join(up.Path, c.fragmentName(i))
o, err := c.obj.GetObjectInfo(ctx, &obj.BucketObject{
Bucket: c.obj.TempBucket(),
Name: name,
})
if err != nil {
if c.obj.IsNotFound(err) {
fragments[i] = &third.GetPutFragment{Url: urls[i]}
continue
}
return nil, err
}
fragments[i] = &third.GetPutFragment{Size: o.Size, Hash: o.Hash, Url: urls[i]}
}
var validTime int64
if up.ValidTime != nil {
validTime = up.ValidTime.UnixMilli()
}
return &third.GetPutResp{
FragmentSize: up.FragmentSize,
Size: up.ObjectSize,
Name: up.Name,
Hash: up.Hash,
Fragments: fragments,
PutURLsHash: up.PutURLsHash,
ContentType: up.ContentType,
ValidTime: validTime,
}, nil
}
func (c *s3Database) ConfirmPut(ctx context.Context, req *third.ConfirmPutReq) (_ *third.ConfirmPutResp, _err error) {
put, err := c.put.Take(ctx, req.PutID)
if err != nil {
return nil, err
}
_, pack := c.getFragmentNum(put.FragmentSize, put.ObjectSize)
defer func() {
if _err == nil {
// 清理上传的碎片
err := c.obj.DeleteObject(ctx, &obj.BucketObject{Bucket: c.obj.TempBucket(), Name: put.Path})
if err != nil {
log.ZError(ctx, "deleteObject failed", err, "Bucket", c.obj.TempBucket(), "Path", put.Path)
}
}
}()
now := time.Now().UnixMilli()
if put.EffectiveTime.UnixMilli() < now {
return nil, errs.ErrFileUploadedExpired.Wrap("put expired")
}
if put.ValidTime != nil && put.ValidTime.UnixMilli() < now {
return nil, errs.ErrFileUploadedExpired.Wrap("object expired")
}
if hash, err := c.hash.Take(ctx, put.Hash, c.obj.Name()); err == nil {
o := relation.ObjectInfoModel{
Name: put.Name,
Hash: hash.Hash,
ValidTime: put.ValidTime,
ContentType: put.ContentType,
CreateTime: time.Now(),
}
if err := c.info.SetObject(ctx, &o); err != nil {
return nil, err
}
defer func() {
err := c.obj.DeleteObject(ctx, &obj.BucketObject{
Bucket: c.obj.TempBucket(),
Name: put.Path,
})
if err != nil {
log.ZError(ctx, "DeleteObject", err, "Bucket", c.obj.TempBucket(), "Path", put.Path)
}
}()
// 服务端已存在
return &third.ConfirmPutResp{
Url: c.urlName(o.Name),
}, nil
} else if !c.isNotFound(err) {
return nil, err
}
src := make([]obj.BucketObject, pack)
for i := 0; i < pack; i++ {
name := path.Join(put.Path, c.fragmentName(i))
o, err := c.obj.GetObjectInfo(ctx, &obj.BucketObject{
Bucket: c.obj.TempBucket(),
Name: name,
})
if err != nil {
return nil, err
}
if i+1 == pack { // 最后一个
size := put.ObjectSize - put.FragmentSize*int64(i)
if size != o.Size {
return nil, fmt.Errorf("last fragment %d size %d not equal to %d hash %s", i, o.Size, size, o.Hash)
}
} else {
if o.Size != put.FragmentSize {
return nil, fmt.Errorf("fragment %d size %d not equal to %d hash %s", i, o.Size, put.FragmentSize, o.Hash)
}
}
src[i] = obj.BucketObject{
Bucket: c.obj.TempBucket(),
Name: name,
}
}
dst := &obj.BucketObject{
Bucket: c.obj.DataBucket(),
Name: c.HashName(put.Hash),
}
if len(src) == 1 { // 未分片直接触发copy
// 检查数据完整性,避免脏数据
o, err := c.obj.GetObjectInfo(ctx, &src[0])
if err != nil {
return nil, err
}
if put.ObjectSize != o.Size {
return nil, fmt.Errorf("size mismatching should %d reality %d", put.ObjectSize, o.Size)
}
if put.Hash != o.Hash {
return nil, fmt.Errorf("hash mismatching should %s reality %s", put.Hash, o.Hash)
}
if err := c.obj.CopyObject(ctx, &src[0], dst); err != nil {
return nil, err
}
} else {
tempBucket := &obj.BucketObject{
Bucket: c.obj.TempBucket(),
Name: path.Join(put.Path, "merge_"+c.UUID()),
}
defer func() { // 清理合成的文件
if err := c.obj.DeleteObject(ctx, tempBucket); err != nil {
log.ZError(ctx, "DeleteObject", err, "Bucket", tempBucket.Bucket, "Path", tempBucket.Name)
}
}()
err := c.obj.ComposeObject(ctx, src, tempBucket)
if err != nil {
return nil, err
}
info, err := c.obj.GetObjectInfo(ctx, tempBucket)
if err != nil {
return nil, err
}
if put.ObjectSize != info.Size {
return nil, fmt.Errorf("size mismatch should %d reality %d", put.ObjectSize, info.Size)
}
if put.Hash != info.Hash {
return nil, fmt.Errorf("hash mismatch should %s reality %s", put.Hash, info.Hash)
}
if err := c.obj.CopyObject(ctx, tempBucket, dst); err != nil {
return nil, err
}
}
h := &relation.ObjectHashModel{
Hash: put.Hash,
Engine: c.obj.Name(),
Size: put.ObjectSize,
Bucket: c.obj.DataBucket(),
Name: dst.Name,
CreateTime: time.Now(),
}
if err := c.hash.Create(ctx, []*relation.ObjectHashModel{h}); err != nil {
return nil, err
}
o := &relation.ObjectInfoModel{
Name: put.Name,
Hash: put.Hash,
ContentType: put.ContentType,
ValidTime: put.ValidTime,
CreateTime: time.Now(),
}
if err := c.info.SetObject(ctx, o); err != nil {
return nil, err
}
if err := c.put.DelPut(ctx, []string{put.PutID}); err != nil {
log.ZError(ctx, "DelPut", err, "PutID", put.PutID)
}
return &third.ConfirmPutResp{
Url: c.urlName(o.Name),
}, nil
}
func (c *s3Database) GetUrl(ctx context.Context, req *third.GetUrlReq) (*third.GetUrlResp, error) {
info, err := c.info.Take(ctx, req.Name)
if err != nil {
return nil, err
}
if info.ValidTime != nil && info.ValidTime.Before(time.Now()) {
return nil, errs.ErrRecordNotFound.Wrap("object expired")
}
hash, err := c.hash.Take(ctx, info.Hash, c.obj.Name())
if err != nil {
return nil, err
}
opt := obj.HeaderOption{ContentType: info.ContentType}
if req.Attachment {
opt.Filename = info.Name
}
u, err := c.obj.PresignedGetURL(ctx, hash.Bucket, hash.Name, time.Duration(req.Expires)*time.Millisecond, &opt)
if err != nil {
return nil, err
}
return &third.GetUrlResp{
Url: u,
Size: hash.Size,
Hash: hash.Hash,
}, nil
}
func (c *s3Database) CleanExpirationObject(ctx context.Context, t time.Time) {
// 清理上传产生的临时文件
c.cleanPutTemp(ctx, t, 10)
// 清理hash引用全过期的文件
c.cleanExpirationObject(ctx, t)
// 清理没有引用的hash对象
c.clearNoCitation(ctx, c.obj.Name(), 10)
}
func (c *s3Database) cleanPutTemp(ctx context.Context, t time.Time, num int) {
for {
puts, err := c.put.FindExpirationPut(ctx, t, num)
if err != nil {
log.ZError(ctx, "FindExpirationPut", err, "Time", t, "Num", num)
return
}
if len(puts) == 0 {
return
}
for _, put := range puts {
err := c.obj.DeleteObject(ctx, &obj.BucketObject{Bucket: c.obj.TempBucket(), Name: put.Path})
if err != nil {
log.ZError(ctx, "DeleteObject", err, "Bucket", c.obj.TempBucket(), "Path", put.Path)
return
}
}
ids := utils.Slice(puts, func(e *relation.ObjectPutModel) string { return e.PutID })
err = c.put.DelPut(ctx, ids)
if err != nil {
log.ZError(ctx, "DelPut", err, "PutID", ids)
return
}
}
}
func (c *s3Database) cleanExpirationObject(ctx context.Context, t time.Time) {
err := c.info.DeleteExpiration(ctx, t)
if err != nil {
log.ZError(ctx, "DeleteExpiration", err, "Time", t)
}
}
func (c *s3Database) clearNoCitation(ctx context.Context, engine string, limit int) {
for {
list, err := c.hash.DeleteNoCitation(ctx, engine, limit)
if err != nil {
log.ZError(ctx, "DeleteNoCitation", err, "Engine", engine, "Limit", limit)
return
}
if len(list) == 0 {
return
}
var hasErr bool
for _, h := range list {
err := c.obj.DeleteObject(ctx, &obj.BucketObject{Bucket: h.Bucket, Name: h.Name})
if err != nil {
hasErr = true
log.ZError(ctx, "DeleteObject", err, "Bucket", h.Bucket, "Path", h.Name)
continue
}
}
if hasErr {
return
}
}
}
func (c *s3Database) GetHashInfo(ctx context.Context, req *third.GetHashInfoReq) (*third.GetHashInfoResp, error) {
if err := c.CheckHash(req.Hash); err != nil {
return nil, err
}
o, err := c.hash.Take(ctx, req.Hash, c.obj.Name())
if err != nil {
return nil, err
}
return &third.GetHashInfoResp{
Hash: o.Hash,
Size: o.Size,
}, nil
}
+28
View File
@@ -0,0 +1,28 @@
package controller
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
)
type ThirdDatabase interface {
FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error
SetAppBadge(ctx context.Context, userID string, value int) error
}
type thirdDatabase struct {
cache cache.MsgModel
}
func NewThirdDatabase(cache cache.MsgModel) ThirdDatabase {
return &thirdDatabase{cache: cache}
}
func (t *thirdDatabase) FcmUpdateToken(ctx context.Context, account string, platformID int, fcmToken string, expireTime int64) error {
return t.cache.SetFcmToken(ctx, account, platformID, fcmToken, expireTime)
}
func (t *thirdDatabase) SetAppBadge(ctx context.Context, userID string, value int) error {
return t.cache.SetUserBadgeUnreadCountSum(ctx, userID, value)
}
+143
View File
@@ -0,0 +1,143 @@
package controller
import (
"context"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
)
type UserDatabase interface {
//获取指定用户的信息 如有userID未找到 也返回错误
FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error)
//获取指定用户的信息 如有userID未找到 不返回错误
Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error)
//插入多条 外部保证userID 不重复 且在db中不存在
Create(ctx context.Context, users []*relation.UserModel) (err error)
//更新(非零值) 外部保证userID存在
Update(ctx context.Context, user *relation.UserModel) (err error)
//更新(零值) 外部保证userID存在
UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error)
//如果没找到,不返回错误
Page(ctx context.Context, pageNumber, showNumber int32) (users []*relation.UserModel, count int64, err error)
//只要有一个存在就为true
IsExist(ctx context.Context, userIDs []string) (exist bool, err error)
//获取所有用户ID
GetAllUserID(ctx context.Context) ([]string, error)
//函数内部先查询db中是否存在,存在则什么都不做;不存在则插入
InitOnce(ctx context.Context, users []*relation.UserModel) (err error)
// 获取用户总数
CountTotal(ctx context.Context) (int64, error)
// 获取范围内用户增量
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
}
type userDatabase struct {
userDB relation.UserModelInterface
cache cache.UserCache
tx tx.Tx
}
func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx) UserDatabase {
return &userDatabase{userDB: userDB, cache: cache, tx: tx}
}
func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) (err error) {
userIDs := utils.Slice(users, func(e *relation.UserModel) string {
return e.UserID
})
result, err := u.userDB.Find(ctx, userIDs)
if err != nil {
return err
}
miss := utils.SliceAnySub(users, result, func(e *relation.UserModel) string { return e.UserID })
if len(miss) > 0 {
_ = u.userDB.Create(ctx, miss)
}
return nil
}
// 获取指定用户的信息 如有userID未找到 也返回错误
func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
users, err = u.cache.GetUsersInfo(ctx, userIDs)
if err != nil {
return
}
if len(users) != len(userIDs) {
err = errs.ErrRecordNotFound.Wrap("userID not found")
}
return
}
// 获取指定用户的信息 如有userID未找到 不返回错误
func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) {
users, err = u.cache.GetUsersInfo(ctx, userIDs)
return
}
// 插入多条 外部保证userID 不重复 且在db中不存在
func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) (err error) {
if err := u.tx.Transaction(func(tx any) error {
err = u.userDB.Create(ctx, users)
if err != nil {
return err
}
return nil
}); err != nil {
return err
}
var userIDs []string
for _, user := range users {
userIDs = append(userIDs, user.UserID)
}
return u.cache.DelUsersInfo(userIDs...).ExecDel(ctx)
}
// 更新(非零值) 外部保证userID存在
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)
}
// 更新(零值) 外部保证userID存在
func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) {
if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil {
return err
}
return u.cache.DelUsersInfo(userID).ExecDel(ctx)
}
// 获取,如果没找到,不返回错误
func (u *userDatabase) Page(ctx context.Context, pageNumber, showNumber int32) (users []*relation.UserModel, count int64, err error) {
return u.userDB.Page(ctx, pageNumber, showNumber)
}
// userIDs是否存在 只要有一个存在就为true
func (u *userDatabase) IsExist(ctx context.Context, userIDs []string) (exist bool, err error) {
users, err := u.userDB.Find(ctx, userIDs)
if err != nil {
return false, err
}
if len(users) > 0 {
return true, nil
}
return false, nil
}
func (u *userDatabase) GetAllUserID(ctx context.Context) (userIDs []string, err error) {
return u.userDB.GetAllUserID(ctx)
}
func (u *userDatabase) CountTotal(ctx context.Context) (count int64, err error) {
return u.userDB.CountTotal(ctx)
}
func (u *userDatabase) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) {
return u.userDB.CountRangeEverydayTotal(ctx, start, end)
}
-49
View File
@@ -1,49 +0,0 @@
package db
type ExtendMsgSet struct {
ID string `bson:"id" json:"ID"`
ExtendMsg []*ExtendMsg `bson:"extend_msg" json:"extendMsg"`
LatestUpdateTime int32 `bson:"latest_update_time" json:"latestUpdateTime"`
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
Ex string `bson:"ex" json:"ex"`
ExtendMsgNum int32 `bson:"extend_msg_num" json:"extendMsgNum"`
CreateTime int32 `bson:"create_time" json:"createTime"`
}
type ExtendMsg struct {
SendID string `bson:"send_id" json:"sendID"`
ServerMsgID string `bson:"server_msg_id" json:"serverMsgID"`
Ex string `bson:"ex" json:"ex"`
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
LikeUserIDList []string `bson:"like_user_id_list" json:"likeUserIDList"`
Content string `bson:"content" json:"content"`
ExtendMsgComments []*ExtendMsgComment `bson:"extend_msg_comments" json:"extendMsgComment"`
Vote *Vote `bson:"vote" json:"vote"`
Urls []string `bson:"urls" json:"urls"`
CreateTime int32 `bson:"create_time" json:"createTime"`
}
type Vote struct {
Content string `bson:"content" json:"content"`
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
Ex string `bson:"ex" json:"ex"`
Options []*Options `bson:"options" json:"options"`
}
type Options struct {
Content string `bson:"content" json:"content"`
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
Ex string `bson:"ex" json:"ex"`
VoteUserIDList []string `bson:"vote_user_id_list" json:"voteUserIDList"`
}
type ExtendMsgComment struct {
UserID string `bson:"user_id" json:"userID"`
ReplyUserID string `bson:"reply_user_id" json:"replyUserID"`
ReplyContentID string `bson:"reply_content_id" json:"replyContentID"`
ContentID string `bson:"content_id" json:"contentID"`
Content string `bson:"content" json:"content"`
CreateTime int32 `bson:"create_time" json:"createTime"`
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
Ex string `bson:"ex" json:"ex"`
}
+67
View File
@@ -0,0 +1,67 @@
package localcache
import (
"context"
"sync"
"github.com/OpenIMSDK/Open-IM-Server/pkg/discoveryregistry"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/conversation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
)
type ConversationLocalCache struct {
lock sync.Mutex
superGroupRecvMsgNotNotifyUserIDs map[string]Hash
conversationIDs map[string]Hash
client *rpcclient.Conversation
}
type Hash struct {
hash uint64
ids []string
}
func NewConversationLocalCache(discov discoveryregistry.SvcDiscoveryRegistry) *ConversationLocalCache {
return &ConversationLocalCache{
superGroupRecvMsgNotNotifyUserIDs: make(map[string]Hash),
conversationIDs: make(map[string]Hash),
client: rpcclient.NewConversation(discov),
}
}
func (g *ConversationLocalCache) GetRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
resp, err := g.client.Client.GetRecvMsgNotNotifyUserIDs(ctx, &conversation.GetRecvMsgNotNotifyUserIDsReq{
GroupID: groupID,
})
if err != nil {
return nil, err
}
return resp.UserIDs, nil
}
func (g *ConversationLocalCache) GetConversationIDs(ctx context.Context, userID string) ([]string, error) {
resp, err := g.client.Client.GetUserConversationIDsHash(ctx, &conversation.GetUserConversationIDsHashReq{
OwnerUserID: userID,
})
if err != nil {
return nil, err
}
g.lock.Lock()
defer g.lock.Unlock()
hash, ok := g.conversationIDs[userID]
if !ok || hash.hash != resp.Hash {
conversationIDsResp, err := g.client.Client.GetConversationIDs(ctx, &conversation.GetConversationIDsReq{
UserID: userID,
})
if err != nil {
return nil, err
}
g.conversationIDs[userID] = Hash{
hash: resp.Hash,
ids: conversationIDsResp.ConversationIDs,
}
return conversationIDsResp.ConversationIDs, nil
}
return hash.ids, nil
}
+59
View File
@@ -0,0 +1,59 @@
package localcache
import (
"context"
"sync"
"github.com/OpenIMSDK/Open-IM-Server/pkg/discoveryregistry"
"github.com/OpenIMSDK/Open-IM-Server/pkg/errs"
"github.com/OpenIMSDK/Open-IM-Server/pkg/proto/group"
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
)
type GroupLocalCache struct {
lock sync.Mutex
cache map[string]GroupMemberIDsHash
client *rpcclient.Group
}
type GroupMemberIDsHash struct {
memberListHash uint64
userIDs []string
}
func NewGroupLocalCache(discov discoveryregistry.SvcDiscoveryRegistry) *GroupLocalCache {
client := rpcclient.NewGroup(discov)
return &GroupLocalCache{
cache: make(map[string]GroupMemberIDsHash, 0),
client: client,
}
}
func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) {
resp, err := g.client.Client.GetGroupAbstractInfo(ctx, &group.GetGroupAbstractInfoReq{
GroupIDs: []string{groupID},
})
if err != nil {
return nil, err
}
if len(resp.GroupAbstractInfos) < 1 {
return nil, errs.ErrGroupIDNotFound
}
g.lock.Lock()
defer g.lock.Unlock()
localHashInfo, ok := g.cache[groupID]
if ok && localHashInfo.memberListHash == resp.GroupAbstractInfos[0].GroupMemberListHash {
return localHashInfo.userIDs, nil
}
groupMembersResp, err := g.client.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{
GroupID: groupID,
})
if err != nil {
return nil, err
}
g.cache[groupID] = GroupMemberIDsHash{
memberListHash: resp.GroupAbstractInfos[0].GroupMemberListHash,
userIDs: groupMembersResp.UserIDs,
}
return g.cache[groupID].userIDs, nil
}
@@ -0,0 +1 @@
package localcache
-135
View File
@@ -1,135 +0,0 @@
package db
import (
"Open_IM/pkg/common/config"
//"Open_IM/pkg/common/log"
"Open_IM/pkg/utils"
"fmt"
go_redis "github.com/go-redis/redis/v8"
"go.mongodb.org/mongo-driver/mongo/options"
"gopkg.in/mgo.v2"
"time"
"context"
//"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
// "go.mongodb.org/mongo-driver/mongo/options"
)
var DB DataBases
type DataBases struct {
MysqlDB mysqlDB
mgoSession *mgo.Session
//redisPool *redis.Pool
mongoClient *mongo.Client
rdb *go_redis.Client
}
func key(dbAddress, dbName string) string {
return dbAddress + "_" + dbName
}
func init() {
//log.NewPrivateLog(constant.LogFileName)
//var mgoSession *mgo.Session
var mongoClient *mongo.Client
var err1 error
//mysql init
initMysqlDB()
// mongo init
// "mongodb://sysop:moon@localhost/records"
uri := "mongodb://sample.host:27017/?maxPoolSize=20&w=majority"
if config.Config.Mongo.DBUri != "" {
// example: mongodb://$user:$password@mongo1.mongo:27017,mongo2.mongo:27017,mongo3.mongo:27017/$DBDatabase/?replicaSet=rs0&readPreference=secondary&authSource=admin&maxPoolSize=$DBMaxPoolSize
uri = config.Config.Mongo.DBUri
} else {
if config.Config.Mongo.DBPassword != "" && config.Config.Mongo.DBUserName != "" {
uri = fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%d", config.Config.Mongo.DBUserName, config.Config.Mongo.DBPassword, config.Config.Mongo.DBAddress[0],
config.Config.Mongo.DBDatabase, config.Config.Mongo.DBMaxPoolSize)
} else {
uri = fmt.Sprintf("mongodb://%s/%s/?maxPoolSize=%d",
config.Config.Mongo.DBAddress[0], config.Config.Mongo.DBDatabase,
config.Config.Mongo.DBMaxPoolSize)
}
}
mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
fmt.Println(" mongo.Connect failed, try ", utils.GetSelfFuncName(), err.Error(), uri)
time.Sleep(time.Duration(30) * time.Second)
mongoClient, err1 = mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err1 != nil {
fmt.Println(" mongo.Connect retry failed, panic", err.Error(), uri)
panic(err1.Error())
}
}
fmt.Println("0", utils.GetSelfFuncName(), "mongo driver client init success: ", uri)
DB.mongoClient = mongoClient
//mgoDailInfo := &mgo.DialInfo{
// Addrs: config.Config.Mongo.DBAddress,
// Direct: config.Config.Mongo.DBDirect,
// Timeout: time.Second * time.Duration(config.Config.Mongo.DBTimeout),
// Database: config.Config.Mongo.DBDatabase,
// Source: config.Config.Mongo.DBSource,
// Username: config.Config.Mongo.DBUserName,
// Password: config.Config.Mongo.DBPassword,
// PoolLimit: config.Config.Mongo.DBMaxPoolSize,
//}
//mgoSession, err = mgo.DialWithInfo(mgoDailInfo)
//
//if err != nil {
//
// mgoSession, err1 = mgo.DialWithInfo(mgoDailInfo)
// if err1 != nil {
// log.NewError(" mongo.Connect failed, panic", err.Error())
// panic(err1.Error())
// }
//}
//DB.mgoSession = mgoSession
//DB.mgoSession.SetMode(mgo.Monotonic, true)
//c := DB.mgoSession.DB(config.Config.Mongo.DBDatabase).C(cChat)
//err = c.EnsureIndexKey("uid")
//if err != nil {
// panic(err.Error())
//}
//
// redis pool init
//DB.redisPool = &redis.Pool{
// MaxIdle: config.Config.Redis.DBMaxIdle,
// MaxActive: config.Config.Redis.DBMaxActive,
// IdleTimeout: time.Duration(config.Config.Redis.DBIdleTimeout) * time.Second,
// Dial: func() (redis.Conn, error) {
// return redis.Dial(
// "tcp",
// config.Config.Redis.DBAddress,
// redis.DialReadTimeout(time.Duration(1000)*time.Millisecond),
// redis.DialWriteTimeout(time.Duration(1000)*time.Millisecond),
// redis.DialConnectTimeout(time.Duration(1000)*time.Millisecond),
// redis.DialDatabase(0),
// redis.DialPassword(config.Config.Redis.DBPassWord),
// )
// },
//}
DB.rdb = go_redis.NewClient(&go_redis.Options{
Addr: config.Config.Redis.DBAddress,
Password: config.Config.Redis.DBPassWord, // no password set
DB: 0, // use default DB
PoolSize: 100, // 连接池大小
})
//DB.rdb = go_redis.NewClusterClient(&go_redis.ClusterOptions{
// Addrs: []string{config.Config.Redis.DBAddress},
// PoolSize: 100,
// Password: config.Config.Redis.DBPassWord,
//})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = DB.rdb.Ping(ctx).Result()
if err != nil {
panic(err.Error())
}
}
-278
View File
@@ -1,278 +0,0 @@
package db
import "time"
type Register struct {
Account string `gorm:"column:account;primary_key;type:char(255)" json:"account"`
Password string `gorm:"column:password;type:varchar(255)" json:"password"`
Ex string `gorm:"column:ex;size:1024" json:"ex"`
UserID string `gorm:"column:user_id;type:varchar(255)" json:"userID"`
}
//
//message FriendInfo{
//string OwnerUserID = 1;
//string Remark = 2;
//int64 CreateTime = 3;
//UserInfo FriendUser = 4;
//int32 AddSource = 5;
//string OperatorUserID = 6;
//string Ex = 7;
//}
//open_im_sdk.FriendInfo(FriendUser) != imdb.Friend(FriendUserID)
type Friend struct {
OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"`
FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"`
Remark string `gorm:"column:remark;size:255"`
CreateTime time.Time `gorm:"column:create_time"`
AddSource int32 `gorm:"column:add_source"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"`
Ex string `gorm:"column:ex;size:1024"`
}
//message FriendRequest{
//string FromUserID = 1;
//string ToUserID = 2;
//int32 HandleResult = 3;
//string ReqMsg = 4;
//int64 CreateTime = 5;
//string HandlerUserID = 6;
//string HandleMsg = 7;
//int64 HandleTime = 8;
//string Ex = 9;
//}
//open_im_sdk.FriendRequest(nickname, farce url ...) != imdb.FriendRequest
type FriendRequest struct {
FromUserID string `gorm:"column:from_user_id;primary_key;size:64"`
ToUserID string `gorm:"column:to_user_id;primary_key;size:64"`
HandleResult int32 `gorm:"column:handle_result"`
ReqMsg string `gorm:"column:req_msg;size:255"`
CreateTime time.Time `gorm:"column:create_time"`
HandlerUserID string `gorm:"column:handler_user_id;size:64"`
HandleMsg string `gorm:"column:handle_msg;size:255"`
HandleTime time.Time `gorm:"column:handle_time"`
Ex string `gorm:"column:ex;size:1024"`
}
func (FriendRequest) TableName() string {
return "friend_requests"
}
//message GroupInfo{
// string GroupID = 1;
// string GroupName = 2;
// string Notification = 3;
// string Introduction = 4;
// string FaceUrl = 5;
// string OwnerUserID = 6;
// uint32 MemberCount = 8;
// int64 CreateTime = 7;
// string Ex = 9;
// int32 Status = 10;
// string CreatorUserID = 11;
// int32 GroupType = 12;
//}
// open_im_sdk.GroupInfo (OwnerUserID , MemberCount )> imdb.Group
type Group struct {
//`json:"operationID" binding:"required"`
//`protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` `json:"operationID" binding:"required"`
GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"`
GroupName string `gorm:"column:name;size:255" json:"groupName"`
Notification string `gorm:"column:notification;size:255" json:"notification"`
Introduction string `gorm:"column:introduction;size:255" json:"introduction"`
FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"`
CreateTime time.Time `gorm:"column:create_time"`
Ex string `gorm:"column:ex" json:"ex;size:1024" json:"ex"`
Status int32 `gorm:"column:status"`
CreatorUserID string `gorm:"column:creator_user_id;size:64"`
GroupType int32 `gorm:"column:group_type"`
}
//message GroupMemberFullInfo {
//string GroupID = 1 ;
//string UserID = 2 ;
//int32 roleLevel = 3;
//int64 JoinTime = 4;
//string NickName = 5;
//string FaceUrl = 6;
//int32 JoinSource = 8;
//string OperatorUserID = 9;
//string Ex = 10;
//int32 AppMangerLevel = 7; //if >0
//} open_im_sdk.GroupMemberFullInfo(AppMangerLevel) > imdb.GroupMember
type GroupMember struct {
GroupID string `gorm:"column:group_id;primary_key;size:64"`
UserID string `gorm:"column:user_id;primary_key;size:64"`
Nickname string `gorm:"column:nickname;size:255"`
FaceURL string `gorm:"column:user_group_face_url;size:255"`
RoleLevel int32 `gorm:"column:role_level"`
JoinTime time.Time `gorm:"column:join_time"`
JoinSource int32 `gorm:"column:join_source"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"`
MuteEndTime time.Time `gorm:"column:mute_end_time"`
Ex string `gorm:"column:ex;size:1024"`
}
//message GroupRequest{
//string UserID = 1;
//string GroupID = 2;
//string HandleResult = 3;
//string ReqMsg = 4;
//string HandleMsg = 5;
//int64 ReqTime = 6;
//string HandleUserID = 7;
//int64 HandleTime = 8;
//string Ex = 9;
//}open_im_sdk.GroupRequest == imdb.GroupRequest
type GroupRequest struct {
UserID string `gorm:"column:user_id;primary_key;size:64"`
GroupID string `gorm:"column:group_id;primary_key;size:64"`
HandleResult int32 `gorm:"column:handle_result"`
ReqMsg string `gorm:"column:req_msg;size:1024"`
HandledMsg string `gorm:"column:handle_msg;size:1024"`
ReqTime time.Time `gorm:"column:req_time"`
HandleUserID string `gorm:"column:handle_user_id;size:64"`
HandledTime time.Time `gorm:"column:handle_time"`
Ex string `gorm:"column:ex;size:1024"`
}
//string UserID = 1;
//string Nickname = 2;
//string FaceUrl = 3;
//int32 Gender = 4;
//string PhoneNumber = 5;
//string Birth = 6;
//string Email = 7;
//string Ex = 8;
//int64 CreateTime = 9;
//int32 AppMangerLevel = 10;
//open_im_sdk.User == imdb.User
type User struct {
UserID string `gorm:"column:user_id;primary_key;size:64"`
Nickname string `gorm:"column:name;size:255"`
FaceURL string `gorm:"column:face_url;size:255"`
Gender int32 `gorm:"column:gender"`
PhoneNumber string `gorm:"column:phone_number;size:32"`
Birth time.Time `gorm:"column:birth"`
Email string `gorm:"column:email;size:64"`
Ex string `gorm:"column:ex;size:1024"`
CreateTime time.Time `gorm:"column:create_time"`
AppMangerLevel int32 `gorm:"column:app_manger_level"`
GlobalRecvMsgOpt int32 `gorm:"column:global_recv_msg_opt"`
}
//message BlackInfo{
//string OwnerUserID = 1;
//int64 CreateTime = 2;
//PublicUserInfo BlackUserInfo = 4;
//int32 AddSource = 5;
//string OperatorUserID = 6;
//string Ex = 7;
//}
// open_im_sdk.BlackInfo(BlackUserInfo) != imdb.Black (BlockUserID)
type Black struct {
OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"`
BlockUserID string `gorm:"column:block_user_id;primary_key;size:64"`
CreateTime time.Time `gorm:"column:create_time"`
AddSource int32 `gorm:"column:add_source"`
OperatorUserID string `gorm:"column:operator_user_id;size:64"`
Ex string `gorm:"column:ex;size:1024"`
}
type ChatLog struct {
ServerMsgID string `gorm:"column:server_msg_id;primary_key;type:char(64)" json:"serverMsgID"`
ClientMsgID string `gorm:"column:client_msg_id;type:char(64)" json:"clientMsgID"`
SendID string `gorm:"column:send_id;type:char(64)" json:"sendID"`
RecvID string `gorm:"column:recv_id;type:char(64)" json:"recvID"`
SenderPlatformID int32 `gorm:"column:sender_platform_id" json:"senderPlatformID"`
SenderNickname string `gorm:"column:sender_nick_name;type:varchar(255)" json:"senderNickname"`
SenderFaceURL string `gorm:"column:sender_face_url;type:varchar(255)" json:"senderFaceURL"`
SessionType int32 `gorm:"column:session_type" json:"sessionType"`
MsgFrom int32 `gorm:"column:msg_from" json:"msgFrom"`
ContentType int32 `gorm:"column:content_type" json:"contentType"`
Content string `gorm:"column:content;type:varchar(3000)" json:"content"`
Status int32 `gorm:"column:status" json:"status"`
SendTime time.Time `gorm:"column:send_time" json:"sendTime"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
}
func (ChatLog) TableName() string {
return "chat_logs"
}
type BlackList struct {
UserId string `gorm:"column:uid"`
BeginDisableTime time.Time `gorm:"column:begin_disable_time"`
EndDisableTime time.Time `gorm:"column:end_disable_time"`
}
type Conversation struct {
OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"`
ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"`
ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"`
UserID string `gorm:"column:user_id;type:char(64)" json:"userID"`
GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"`
RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"`
UnreadCount int32 `gorm:"column:unread_count" json:"unreadCount"`
DraftTextTime int64 `gorm:"column:draft_text_time" json:"draftTextTime"`
IsPinned bool `gorm:"column:is_pinned" json:"isPinned"`
IsPrivateChat bool `gorm:"column:is_private_chat" json:"isPrivateChat"`
GroupAtType int32 `gorm:"column:group_at_type" json:"groupAtType"`
IsNotInGroup bool `gorm:"column:is_not_in_group" json:"isNotInGroup"`
UpdateUnreadCountTime int64 `gorm:"column:update_unread_count_time" json:"updateUnreadCountTime"`
AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"`
Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
}
func (Conversation) TableName() string {
return "conversations"
}
type Department struct {
DepartmentID string `gorm:"column:department_id;primary_key;size:64" json:"departmentID"`
FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"`
Name string `gorm:"column:name;size:256" json:"name" binding:"required"`
ParentID string `gorm:"column:parent_id;size:64" json:"parentID" binding:"required"` // "0" or Real parent id
Order int32 `gorm:"column:order" json:"order" ` // 1, 2, ...
DepartmentType int32 `gorm:"column:department_type" json:"departmentType"` //1, 2...
RelatedGroupID string `gorm:"column:related_group_id;size:64" json:"relatedGroupID"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
}
func (Department) TableName() string {
return "departments"
}
type OrganizationUser struct {
UserID string `gorm:"column:user_id;primary_key;size:64"`
Nickname string `gorm:"column:nickname;size:256"`
EnglishName string `gorm:"column:english_name;size:256"`
FaceURL string `gorm:"column:face_url;size:256"`
Gender int32 `gorm:"column:gender"` //1 ,2
Mobile string `gorm:"column:mobile;size:32"`
Telephone string `gorm:"column:telephone;size:32"`
Birth time.Time `gorm:"column:birth"`
Email string `gorm:"column:email;size:64"`
CreateTime time.Time `gorm:"column:create_time"`
Ex string `gorm:"column:ex;size:1024"`
}
func (OrganizationUser) TableName() string {
return "organization_users"
}
type DepartmentMember struct {
UserID string `gorm:"column:user_id;primary_key;size:64"`
DepartmentID string `gorm:"column:department_id;primary_key;size:64"`
Order int32 `gorm:"column:order" json:"order"` //1,2
Position string `gorm:"column:position;size:256" json:"position"`
Leader int32 `gorm:"column:leader" json:"leader"` //-1, 1
Status int32 `gorm:"column:status" json:"status"` //-1, 1
CreateTime time.Time `gorm:"column:create_time"`
Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"`
}
func (DepartmentMember) TableName() string {
return "department_members"
}
-833
View File
@@ -1,833 +0,0 @@
package db
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/log"
pbMsg "Open_IM/pkg/proto/msg"
open_im_sdk "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"errors"
"fmt"
"github.com/gogo/protobuf/sortkeys"
"go.mongodb.org/mongo-driver/mongo/options"
"math/rand"
"sync"
//"github.com/garyburd/redigo/redis"
"github.com/golang/protobuf/proto"
"gopkg.in/mgo.v2/bson"
"strconv"
"time"
)
const cChat = "msg"
const cGroup = "group"
const cTag = "tag"
const cSendLog = "send_log"
const singleGocMsgNum = 5000
func GetSingleGocMsgNum() int {
return singleGocMsgNum
}
type MsgInfo struct {
SendTime int64
Msg []byte
}
type UserChat struct {
UID string
Msg []MsgInfo
}
type GroupMember_x struct {
GroupID string
UIDList []string
}
func (d *DataBases) GetMinSeqFromMongo(uid string) (MinSeq uint32, err error) {
return 1, nil
//var i, NB uint32
//var seqUid string
//session := d.mgoSession.Clone()
//if session == nil {
// return MinSeq, errors.New("session == nil")
//}
//defer session.Close()
//c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
//MaxSeq, err := d.GetUserMaxSeq(uid)
//if err != nil && err != redis.ErrNil {
// return MinSeq, err
//}
//NB = uint32(MaxSeq / singleGocMsgNum)
//for i = 0; i <= NB; i++ {
// seqUid = indexGen(uid, i)
// n, err := c.Find(bson.M{"uid": seqUid}).Count()
// if err == nil && n != 0 {
// if i == 0 {
// MinSeq = 1
// } else {
// MinSeq = uint32(i * singleGocMsgNum)
// }
// break
// }
//}
//return MinSeq, nil
}
func (d *DataBases) GetMinSeqFromMongo2(uid string) (MinSeq uint32, err error) {
return 1, nil
}
// deleteMsgByLogic
func (d *DataBases) DelMsgBySeqList(userID string, seqList []uint32, operationID string) (err error) {
log.Debug(operationID, utils.GetSelfFuncName(), "args ", userID, seqList)
sortkeys.Uint32s(seqList)
suffixUserID2SubSeqList := func(uid string, seqList []uint32) map[string][]uint32 {
t := make(map[string][]uint32)
for i := 0; i < len(seqList); i++ {
seqUid := getSeqUid(uid, seqList[i])
if value, ok := t[seqUid]; !ok {
var temp []uint32
t[seqUid] = append(temp, seqList[i])
} else {
t[seqUid] = append(value, seqList[i])
}
}
return t
}(userID, seqList)
var wg sync.WaitGroup
wg.Add(len(suffixUserID2SubSeqList))
for k, v := range suffixUserID2SubSeqList {
go func(suffixUserID string, subSeqList []uint32, operationID string) {
if e := d.DelMsgBySeqListInOneDoc(suffixUserID, subSeqList, operationID); e != nil {
log.Error(operationID, "DelMsgBySeqListInOneDoc failed ", e.Error(), suffixUserID, subSeqList)
err = e
}
wg.Done()
}(k, v, operationID)
}
wg.Wait()
return err
}
func (d *DataBases) DelMsgBySeqListInOneDoc(suffixUserID string, seqList []uint32, operationID string) error {
log.Debug(operationID, utils.GetSelfFuncName(), "args ", suffixUserID, seqList)
seqMsgList, indexList, err := d.GetMsgAndIndexBySeqListInOneMongo2(suffixUserID, seqList, operationID)
if err != nil {
return utils.Wrap(err, "")
}
for i, v := range seqMsgList {
if err := d.ReplaceMsgByIndex(suffixUserID, v, operationID, indexList[i]); err != nil {
return utils.Wrap(err, "")
}
}
return nil
}
// deleteMsgByLogic
func (d *DataBases) DelMsgLogic(uid string, seqList []uint32, operationID string) error {
sortkeys.Uint32s(seqList)
seqMsgs, err := d.GetMsgBySeqListMongo2(uid, seqList, operationID)
if err != nil {
return utils.Wrap(err, "")
}
for _, seqMsg := range seqMsgs {
log.NewDebug(operationID, utils.GetSelfFuncName(), *seqMsg)
seqMsg.Status = constant.MsgDeleted
if err = d.ReplaceMsgBySeq(uid, seqMsg, operationID); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), "ReplaceMsgListBySeq error", err.Error())
}
}
return nil
}
func (d *DataBases) ReplaceMsgByIndex(suffixUserID string, msg *open_im_sdk.MsgData, operationID string, seqIndex int) error {
log.NewInfo(operationID, utils.GetSelfFuncName(), suffixUserID, *msg)
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
s := fmt.Sprintf("msg.%d.msg", seqIndex)
log.NewDebug(operationID, utils.GetSelfFuncName(), seqIndex, s)
msg.Status = constant.MsgDeleted
bytes, err := proto.Marshal(msg)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), "proto marshal failed ", err.Error(), msg.String())
return utils.Wrap(err, "")
}
updateResult, err := c.UpdateOne(ctx, bson.M{"uid": suffixUserID}, bson.M{"$set": bson.M{s: bytes}})
log.NewInfo(operationID, utils.GetSelfFuncName(), updateResult)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), "UpdateOne", err.Error())
return utils.Wrap(err, "")
}
return nil
}
func (d *DataBases) ReplaceMsgBySeq(uid string, msg *open_im_sdk.MsgData, operationID string) error {
log.NewInfo(operationID, utils.GetSelfFuncName(), uid, *msg)
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
uid = getSeqUid(uid, msg.Seq)
seqIndex := getMsgIndex(msg.Seq)
s := fmt.Sprintf("msg.%d.msg", seqIndex)
log.NewDebug(operationID, utils.GetSelfFuncName(), seqIndex, s)
bytes, err := proto.Marshal(msg)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), "proto marshal", err.Error())
return utils.Wrap(err, "")
}
updateResult, err := c.UpdateOne(
ctx, bson.M{"uid": uid},
bson.M{"$set": bson.M{s: bytes}})
log.NewInfo(operationID, utils.GetSelfFuncName(), updateResult)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), "UpdateOne", err.Error())
return utils.Wrap(err, "")
}
return nil
}
func (d *DataBases) GetMsgBySeqList(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) {
log.NewInfo(operationID, utils.GetSelfFuncName(), uid, seqList)
var hasSeqList []uint32
singleCount := 0
session := d.mgoSession.Clone()
if session == nil {
return nil, errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
m := func(uid string, seqList []uint32) map[string][]uint32 {
t := make(map[string][]uint32)
for i := 0; i < len(seqList); i++ {
seqUid := getSeqUid(uid, seqList[i])
if value, ok := t[seqUid]; !ok {
var temp []uint32
t[seqUid] = append(temp, seqList[i])
} else {
t[seqUid] = append(value, seqList[i])
}
}
return t
}(uid, seqList)
sChat := UserChat{}
for seqUid, value := range m {
if err = c.Find(bson.M{"uid": seqUid}).One(&sChat); err != nil {
log.NewError(operationID, "not find seqUid", seqUid, value, uid, seqList, err.Error())
continue
}
singleCount = 0
for i := 0; i < len(sChat.Msg); i++ {
msg := new(open_im_sdk.MsgData)
if err = proto.Unmarshal(sChat.Msg[i].Msg, msg); err != nil {
log.NewError(operationID, "Unmarshal err", seqUid, value, uid, seqList, err.Error())
return nil, err
}
if isContainInt32(msg.Seq, value) {
seqMsg = append(seqMsg, msg)
hasSeqList = append(hasSeqList, msg.Seq)
singleCount++
if singleCount == len(value) {
break
}
}
}
}
if len(hasSeqList) != len(seqList) {
var diff []uint32
diff = utils.Difference(hasSeqList, seqList)
exceptionMSg := genExceptionMessageBySeqList(diff)
seqMsg = append(seqMsg, exceptionMSg...)
}
return seqMsg, nil
}
func (d *DataBases) GetMsgBySeqListMongo2(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) {
var hasSeqList []uint32
singleCount := 0
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
m := func(uid string, seqList []uint32) map[string][]uint32 {
t := make(map[string][]uint32)
for i := 0; i < len(seqList); i++ {
seqUid := getSeqUid(uid, seqList[i])
if value, ok := t[seqUid]; !ok {
var temp []uint32
t[seqUid] = append(temp, seqList[i])
} else {
t[seqUid] = append(value, seqList[i])
}
}
return t
}(uid, seqList)
sChat := UserChat{}
for seqUid, value := range m {
if err = c.FindOne(ctx, bson.M{"uid": seqUid}).Decode(&sChat); err != nil {
log.NewError(operationID, "not find seqUid", seqUid, value, uid, seqList, err.Error())
continue
}
singleCount = 0
for i := 0; i < len(sChat.Msg); i++ {
msg := new(open_im_sdk.MsgData)
if err = proto.Unmarshal(sChat.Msg[i].Msg, msg); err != nil {
log.NewError(operationID, "Unmarshal err", seqUid, value, uid, seqList, err.Error())
return nil, err
}
if isContainInt32(msg.Seq, value) {
seqMsg = append(seqMsg, msg)
hasSeqList = append(hasSeqList, msg.Seq)
singleCount++
if singleCount == len(value) {
break
}
}
}
}
if len(hasSeqList) == 0 {
return nil, errors.New("pull message is null")
}
if len(hasSeqList) != len(seqList) {
var diff []uint32
diff = utils.Difference(hasSeqList, seqList)
exceptionMSg := genExceptionMessageBySeqList(diff)
seqMsg = append(seqMsg, exceptionMSg...)
}
return seqMsg, nil
}
func (d *DataBases) GetMsgAndIndexBySeqListInOneMongo2(suffixUserID string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, indexList []int, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
sChat := UserChat{}
if err = c.FindOne(ctx, bson.M{"uid": suffixUserID}).Decode(&sChat); err != nil {
log.NewError(operationID, "not find seqUid", suffixUserID, err.Error())
return nil, nil, utils.Wrap(err, "")
}
singleCount := 0
var hasSeqList []uint32
for i := 0; i < len(sChat.Msg); i++ {
msg := new(open_im_sdk.MsgData)
if err = proto.Unmarshal(sChat.Msg[i].Msg, msg); err != nil {
log.NewError(operationID, "Unmarshal err", msg.String(), err.Error())
return nil, nil, err
}
if isContainInt32(msg.Seq, seqList) {
indexList = append(indexList, i)
seqMsg = append(seqMsg, msg)
hasSeqList = append(hasSeqList, msg.Seq)
singleCount++
if singleCount == len(seqList) {
break
}
}
}
return seqMsg, indexList, nil
}
func genExceptionMessageBySeqList(seqList []uint32) (exceptionMsg []*open_im_sdk.MsgData) {
for _, v := range seqList {
msg := new(open_im_sdk.MsgData)
msg.Seq = v
exceptionMsg = append(exceptionMsg, msg)
}
return exceptionMsg
}
func (d *DataBases) SaveUserChatMongo2(uid string, sendTime int64, m *pbMsg.MsgDataToDB) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
newTime := getCurrentTimestampByMill()
operationID := ""
seqUid := getSeqUid(uid, m.MsgData.Seq)
filter := bson.M{"uid": seqUid}
var err error
sMsg := MsgInfo{}
sMsg.SendTime = sendTime
if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil {
return utils.Wrap(err, "")
}
err = c.FindOneAndUpdate(ctx, filter, bson.M{"$push": bson.M{"msg": sMsg}}).Err()
log.NewWarn(operationID, "get mgoSession cost time", getCurrentTimestampByMill()-newTime)
if err != nil {
sChat := UserChat{}
sChat.UID = seqUid
sChat.Msg = append(sChat.Msg, sMsg)
if _, err = c.InsertOne(ctx, &sChat); err != nil {
log.NewDebug(operationID, "InsertOne failed", filter)
return utils.Wrap(err, "")
}
} else {
log.NewDebug(operationID, "FindOneAndUpdate ok", filter)
}
log.NewDebug(operationID, "find mgo uid cost time", getCurrentTimestampByMill()-newTime)
return nil
}
//
//func (d *DataBases) SaveUserChatListMongo2(uid string, sendTime int64, msgList []*pbMsg.MsgDataToDB) error {
// ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
// c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
// newTime := getCurrentTimestampByMill()
// operationID := ""
// seqUid := ""
// msgListToMongo := make([]MsgInfo, 0)
//
// for _, m := range msgList {
// seqUid = getSeqUid(uid, m.MsgData.Seq)
// var err error
// sMsg := MsgInfo{}
// sMsg.SendTime = sendTime
// if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil {
// return utils.Wrap(err, "")
// }
// msgListToMongo = append(msgListToMongo, sMsg)
// }
//
// filter := bson.M{"uid": seqUid}
// log.NewDebug(operationID, "filter ", seqUid)
// err := c.FindOneAndUpdate(ctx, filter, bson.M{"$push": bson.M{"msg": bson.M{"$each": msgListToMongo}}}).Err()
// log.NewWarn(operationID, "get mgoSession cost time", getCurrentTimestampByMill()-newTime)
// if err != nil {
// sChat := UserChat{}
// sChat.UID = seqUid
// sChat.Msg = msgListToMongo
//
// if _, err = c.InsertOne(ctx, &sChat); err != nil {
// log.NewError(operationID, "InsertOne failed", filter, err.Error(), sChat)
// return utils.Wrap(err, "")
// }
// } else {
// log.NewDebug(operationID, "FindOneAndUpdate ok", filter)
// }
//
// log.NewDebug(operationID, "find mgo uid cost time", getCurrentTimestampByMill()-newTime)
// return nil
//}
func (d *DataBases) SaveUserChat(uid string, sendTime int64, m *pbMsg.MsgDataToDB) error {
var seqUid string
newTime := getCurrentTimestampByMill()
session := d.mgoSession.Clone()
if session == nil {
return errors.New("session == nil")
}
defer session.Close()
log.NewDebug("", "get mgoSession cost time", getCurrentTimestampByMill()-newTime)
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
seqUid = getSeqUid(uid, m.MsgData.Seq)
n, err := c.Find(bson.M{"uid": seqUid}).Count()
if err != nil {
return err
}
log.NewDebug("", "find mgo uid cost time", getCurrentTimestampByMill()-newTime)
sMsg := MsgInfo{}
sMsg.SendTime = sendTime
if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil {
return err
}
if n == 0 {
sChat := UserChat{}
sChat.UID = seqUid
sChat.Msg = append(sChat.Msg, sMsg)
err = c.Insert(&sChat)
if err != nil {
return err
}
} else {
err = c.Update(bson.M{"uid": seqUid}, bson.M{"$push": bson.M{"msg": sMsg}})
if err != nil {
return err
}
}
log.NewDebug("", "insert mgo data cost time", getCurrentTimestampByMill()-newTime)
return nil
}
func (d *DataBases) DelUserChat(uid string) error {
return nil
//session := d.mgoSession.Clone()
//if session == nil {
// return errors.New("session == nil")
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
//
//delTime := time.Now().Unix() - int64(config.Config.Mongo.DBRetainChatRecords)*24*3600
//if err := c.Update(bson.M{"uid": uid}, bson.M{"$pull": bson.M{"msg": bson.M{"sendtime": bson.M{"$lte": delTime}}}}); err != nil {
// return err
//}
//
//return nil
}
func (d *DataBases) DelUserChatMongo2(uid string) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
filter := bson.M{"uid": uid}
delTime := time.Now().Unix() - int64(config.Config.Mongo.DBRetainChatRecords)*24*3600
if _, err := c.UpdateOne(ctx, filter, bson.M{"$pull": bson.M{"msg": bson.M{"sendtime": bson.M{"$lte": delTime}}}}); err != nil {
return utils.Wrap(err, "")
}
return nil
}
func (d *DataBases) MgoUserCount() (int, error) {
return 0, nil
//session := d.mgoSession.Clone()
//if session == nil {
// return 0, errors.New("session == nil")
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
//
//return c.Find(nil).Count()
}
func (d *DataBases) MgoSkipUID(count int) (string, error) {
return "", nil
//session := d.mgoSession.Clone()
//if session == nil {
// return "", errors.New("session == nil")
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
//
//sChat := UserChat{}
//c.Find(nil).Skip(count).Limit(1).One(&sChat)
//return sChat.UID, nil
}
func (d *DataBases) GetGroupMember(groupID string) []string {
return nil
//groupInfo := GroupMember_x{}
//groupInfo.GroupID = groupID
//groupInfo.UIDList = make([]string, 0)
//
//session := d.mgoSession.Clone()
//if session == nil {
// return groupInfo.UIDList
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
//
//if err := c.Find(bson.M{"groupid": groupInfo.GroupID}).One(&groupInfo); err != nil {
// return groupInfo.UIDList
//}
//
//return groupInfo.UIDList
}
func (d *DataBases) AddGroupMember(groupID, uid string) error {
return nil
//session := d.mgoSession.Clone()
//if session == nil {
// return errors.New("session == nil")
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
//
//n, err := c.Find(bson.M{"groupid": groupID}).Count()
//if err != nil {
// return err
//}
//
//if n == 0 {
// groupInfo := GroupMember_x{}
// groupInfo.GroupID = groupID
// groupInfo.UIDList = append(groupInfo.UIDList, uid)
// err = c.Insert(&groupInfo)
// if err != nil {
// return err
// }
//} else {
// err = c.Update(bson.M{"groupid": groupID}, bson.M{"$addToSet": bson.M{"uidlist": uid}})
// if err != nil {
// return err
// }
//}
//
//return nil
}
func (d *DataBases) DelGroupMember(groupID, uid string) error {
return nil
//session := d.mgoSession.Clone()
//if session == nil {
// return errors.New("session == nil")
//}
//defer session.Close()
//
//c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
//
//if err := c.Update(bson.M{"groupid": groupID}, bson.M{"$pull": bson.M{"uidlist": uid}}); err != nil {
// return err
//}
//
//return nil
}
type Tag struct {
UserID string `bson:"user_id"`
TagID string `bson:"tag_id"`
TagName string `bson:"tag_name"`
UserList []string `bson:"user_list"`
}
func (d *DataBases) GetUserTags(userID string) ([]Tag, error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
var tags []Tag
cursor, err := c.Find(ctx, bson.M{"user_id": userID})
if err != nil {
return tags, err
}
if err = cursor.All(ctx, &tags); err != nil {
return tags, err
}
return tags, nil
}
func (d *DataBases) CreateTag(userID, tagName string, userList []string) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
tagID := generateTagID(tagName, userID)
tag := Tag{
UserID: userID,
TagID: tagID,
TagName: tagName,
UserList: userList,
}
_, err := c.InsertOne(ctx, tag)
return err
}
func (d *DataBases) GetTagByID(userID, tagID string) (Tag, error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
var tag Tag
err := c.FindOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}).Decode(&tag)
return tag, err
}
func (d *DataBases) DeleteTag(userID, tagID string) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
_, err := c.DeleteOne(ctx, bson.M{"user_id": userID, "tag_id": tagID})
return err
}
func (d *DataBases) SetTag(userID, tagID, newName string, increaseUserIDList []string, reduceUserIDList []string) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
var tag Tag
if err := c.FindOne(ctx, bson.M{"tag_id": tagID, "user_id": userID}).Decode(&tag); err != nil {
return err
}
if newName != "" {
_, err := c.UpdateOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}, bson.M{"$set": bson.M{"tag_name": newName}})
if err != nil {
return err
}
}
tag.UserList = append(tag.UserList, increaseUserIDList...)
tag.UserList = utils.RemoveRepeatedStringInList(tag.UserList)
for _, v := range reduceUserIDList {
for i2, v2 := range tag.UserList {
if v == v2 {
tag.UserList[i2] = ""
}
}
}
var newUserList []string
for _, v := range tag.UserList {
if v != "" {
newUserList = append(newUserList, v)
}
}
_, err := c.UpdateOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}, bson.M{"$set": bson.M{"user_list": newUserList}})
if err != nil {
return err
}
return nil
}
func (d *DataBases) GetUserIDListByTagID(userID, tagID string) ([]string, error) {
var tag Tag
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag)
_ = c.FindOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}).Decode(&tag)
return tag.UserList, nil
}
type TagUser struct {
UserID string `bson:"user_id"`
UserName string `bson:"user_name"`
}
type TagSendLog struct {
UserList []TagUser `bson:"tag_list"`
SendID string `bson:"send_id"`
SenderPlatformID int32 `bson:"sender_platform_id"`
Content string `bson:"content"`
SendTime int64 `bson:"send_time"`
}
func (d *DataBases) SaveTagSendLog(tagSendLog *TagSendLog) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSendLog)
_, err := c.InsertOne(ctx, tagSendLog)
return err
}
func (d *DataBases) GetTagSendLogs(userID string, showNumber, pageNumber int32) ([]TagSendLog, error) {
var tagSendLogs []TagSendLog
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSendLog)
findOpts := options.Find().SetLimit(int64(showNumber)).SetSkip(int64(showNumber) * (int64(pageNumber) - 1)).SetSort(bson.M{"send_time": -1})
cursor, err := c.Find(ctx, bson.M{"send_id": userID}, findOpts)
if err != nil {
return tagSendLogs, err
}
err = cursor.All(ctx, &tagSendLogs)
if err != nil {
return tagSendLogs, err
}
return tagSendLogs, nil
}
type WorkMoment struct {
WorkMomentID string `bson:"work_moment_id"`
UserID string `bson:"user_id"`
Content string `bson:"content"`
LikeUsers []*LikeUser `bson:"like_users"`
Comments []*Comment `bson:"comments"`
WhoCanSeeUserIDList []string `bson:"who_can_see_user_id_list"`
WhoCantSeeUserIDList []string `bson:"who_cant_see_user_id_list"`
IsPrivate bool
IsPublic bool
CreateTime int32
}
type LikeUser struct {
UserID string
UserName string
}
type Comment struct {
UserID string
UserName string
ReplyUserID string
ReplyUserName string
ContentID string
Content string
CreateTime int32
}
func (d *DataBases) CreateOneWorkMoment(workMoment *WorkMoment) error {
return nil
}
func (d *DataBases) DeleteOneWorkMoment(workMomentID string) error {
return nil
}
func (d *DataBases) GetWorkMomentByID(workMomentID string) (*WorkMoment, error) {
return nil, nil
}
func (d *DataBases) LikeOneWorkMoment(likeUserID, workMomentID string) error {
return nil
}
func (d *DataBases) SetUserWorkMomentsLevel(userID string, level int32) error {
return nil
}
func (d *DataBases) ClearUserWorkMomentsCommentsMsg(userID string) error {
return nil
}
type CommentMsg struct {
WorkMomentID string `bson:"workMoment"`
CommentContent string `bson:"content"`
Comment
}
func (d *DataBases) GetUserWorkMomentsCommentsMsg(userID string, showNumber, pageNumber int32) ([]CommentMsg, error) {
return nil, nil
}
func (d *DataBases) CommentOneWorkMoment(comment Comment, workMomentID string) error {
return nil
}
func (d *DataBases) GetUserWorkMoments(userID string, showNumber, pageNumber int32) ([]WorkMoment, error) {
return nil, nil
}
func (d *DataBases) GetUserFriendWorkMoments(friendIDList []string, showNumber, pageNumber int32) ([]WorkMoment, error) {
return nil, nil
}
func generateTagID(tagName, userID string) string {
return utils.Md5(tagName + userID + strconv.Itoa(rand.Int()) + time.Now().String())
}
func generateWorkMomentID(userID string) string {
return utils.Md5(userID + strconv.Itoa(rand.Int()) + time.Now().String())
}
func getCurrentTimestampByMill() int64 {
return time.Now().UnixNano() / 1e6
}
func getSeqUid(uid string, seq uint32) string {
seqSuffix := seq / singleGocMsgNum
return indexGen(uid, seqSuffix)
}
func GetSeqUid(uid string, seq uint32) string {
return getSeqUid(uid, seq)
}
func getMsgIndex(seq uint32) int {
seqSuffix := seq / singleGocMsgNum
var index uint32
if seqSuffix == 0 {
index = (seq - seqSuffix*singleGocMsgNum) - 1
} else {
index = seq - seqSuffix*singleGocMsgNum
}
return int(index)
}
func isContainInt32(target uint32, List []uint32) bool {
for _, element := range List {
if target == element {
return true
}
}
return false
}
func indexGen(uid string, seqSuffix uint32) string {
return uid + ":" + strconv.FormatInt(int64(seqSuffix), 10)
}
-174
View File
@@ -1,174 +0,0 @@
package db
import (
"Open_IM/pkg/common/config"
"fmt"
"sync"
"time"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type mysqlDB struct {
sync.RWMutex
dbMap map[string]*gorm.DB
}
func initMysqlDB() {
fmt.Println("init mysqlDB start")
//When there is no open IM database, connect to the mysql built-in database to create openIM database
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], "mysql")
var db *gorm.DB
var err1 error
db, err := gorm.Open("mysql", dsn)
if err != nil {
fmt.Println("0", "Open failed ", err.Error(), dsn)
}
if err != nil {
time.Sleep(time.Duration(30) * time.Second)
db, err1 = gorm.Open("mysql", dsn)
if err1 != nil {
fmt.Println("0", "Open failed ", err1.Error(), dsn)
panic(err1.Error())
}
}
//Check the database and table during initialization
sql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8 COLLATE utf8_general_ci;", config.Config.Mysql.DBDatabaseName)
err = db.Exec(sql).Error
if err != nil {
fmt.Println("0", "Exec failed ", err.Error(), sql)
panic(err.Error())
}
db.Close()
dsn = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName)
db, err = gorm.Open("mysql", dsn)
if err != nil {
fmt.Println("0", "Open failed ", err.Error(), dsn)
panic(err.Error())
}
sqlDB, err := db.DB()
if err != nil {
panic(err.Error())
}
sqlDB.SetConnMaxLifetime(time.Second * time.Duration(config.Config.Mysql.DBMaxLifeTime))
sqlDB.SetMaxOpenConns(config.Config.Mysql.DBMaxOpenConns)
sqlDB.SetMaxIdleConns(config.Config.Mysql.DBMaxIdleConns)
fmt.Println("open db ok ", dsn)
db.AutoMigrate(
&Register{},
&Friend{},
&FriendRequest{},
&Group{},
&GroupMember{},
&GroupRequest{},
&User{},
&Black{}, &ChatLog{}, &Register{}, &Conversation{}, &AppVersion{}, &Department{})
db.Set("gorm:table_options", "CHARSET=utf8")
db.Set("gorm:table_options", "collation=utf8_unicode_ci")
if !db.HasTable(&Friend{}) {
fmt.Println("CreateTable Friend")
db.CreateTable(&Friend{})
}
if !db.HasTable(&FriendRequest{}) {
fmt.Println("CreateTable FriendRequest")
db.CreateTable(&FriendRequest{})
}
if !db.HasTable(&Group{}) {
fmt.Println("CreateTable Group")
db.CreateTable(&Group{})
}
if !db.HasTable(&GroupMember{}) {
fmt.Println("CreateTable GroupMember")
db.CreateTable(&GroupMember{})
}
if !db.HasTable(&GroupRequest{}) {
fmt.Println("CreateTable GroupRequest")
db.CreateTable(&GroupRequest{})
}
if !db.HasTable(&User{}) {
fmt.Println("CreateTable User")
db.CreateTable(&User{})
}
if !db.HasTable(&Black{}) {
fmt.Println("CreateTable Black")
db.CreateTable(&Black{})
}
if !db.HasTable(&ChatLog{}) {
fmt.Println("CreateTable ChatLog")
db.CreateTable(&ChatLog{})
}
if !db.HasTable(&Register{}) {
fmt.Println("CreateTable Register")
db.CreateTable(&Register{})
}
if !db.HasTable(&Conversation{}) {
fmt.Println("CreateTable Conversation")
db.CreateTable(&Conversation{})
}
if !db.HasTable(&Department{}) {
fmt.Println("CreateTable Department")
db.CreateTable(&Department{})
}
if !db.HasTable(&OrganizationUser{}) {
fmt.Println("CreateTable OrganizationUser")
db.CreateTable(&OrganizationUser{})
}
if !db.HasTable(&DepartmentMember{}) {
fmt.Println("CreateTable DepartmentMember")
db.CreateTable(&DepartmentMember{})
}
return
}
func (m *mysqlDB) DefaultGormDB() (*gorm.DB, error) {
return m.GormDB(config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName)
}
func (m *mysqlDB) GormDB(dbAddress, dbName string) (*gorm.DB, error) {
m.Lock()
defer m.Unlock()
k := key(dbAddress, dbName)
if _, ok := m.dbMap[k]; !ok {
if err := m.open(dbAddress, dbName); err != nil {
return nil, err
}
}
return m.dbMap[k], nil
}
func (m *mysqlDB) open(dbAddress, dbName string) error {
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, dbAddress, dbName)
db, err := gorm.Open("mysql", dsn)
if err != nil {
return err
}
db.SingularTable(true)
db.DB().SetMaxOpenConns(config.Config.Mysql.DBMaxOpenConns)
db.DB().SetMaxIdleConns(config.Config.Mysql.DBMaxIdleConns)
db.DB().SetConnMaxLifetime(time.Duration(config.Config.Mysql.DBMaxLifeTime) * time.Second)
if m.dbMap == nil {
m.dbMap = make(map[string]*gorm.DB)
}
k := key(dbAddress, dbName)
m.dbMap[k] = db
return nil
}
@@ -1,145 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/log"
"Open_IM/pkg/utils"
)
func SetConversation(conversation db.Conversation) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
dbConn.LogMode(false)
newConversation := conversation
if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 {
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create")
return dbConn.Model(&db.Conversation{}).Create(conversation).Error
// if exist, then update record
} else {
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update")
//force update
return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID).
Update(map[string]interface{}{"recv_msg_opt": conversation.RecvMsgOpt, "is_pinned": conversation.IsPinned, "is_private_chat": conversation.IsPrivateChat,
"group_at_type": conversation.GroupAtType, "is_not_in_group": conversation.IsNotInGroup}).Error
}
}
func SetOneConversation(conversation db.Conversation) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
dbConn.LogMode(false)
return dbConn.Model(&db.Conversation{}).Create(conversation).Error
}
func PeerUserSetConversation(conversation db.Conversation) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
dbConn.LogMode(false)
newConversation := conversation
if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 {
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create")
return dbConn.Model(&db.Conversation{}).Create(conversation).Error
// if exist, then update record
}
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update")
//force update
return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID).
Update(map[string]interface{}{"is_private_chat": conversation.IsPrivateChat}).Error
}
func SetRecvMsgOpt(conversation db.Conversation) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
dbConn.LogMode(false)
newConversation := conversation
if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 {
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create")
return dbConn.Model(&db.Conversation{}).Create(conversation).Error
// if exist, then update record
} else {
log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update")
//force update
return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID).
Update(map[string]interface{}{"recv_msg_opt": conversation.RecvMsgOpt}).Error
}
}
func GetUserAllConversations(ownerUserID string) ([]db.Conversation, error) {
var conversations []db.Conversation
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return conversations, err
}
dbConn.LogMode(false)
err = dbConn.Model(&db.Conversation{}).Where("owner_user_id=?", ownerUserID).Find(&conversations).Error
return conversations, err
}
func GetMultipleUserConversationByConversationID(ownerUserIDList []string, conversationID string) ([]db.Conversation, error) {
var conversations []db.Conversation
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return conversations, err
}
dbConn.LogMode(false)
err = dbConn.Model(&db.Conversation{}).Where("owner_user_id IN ? and conversation_id=?", ownerUserIDList, conversationID).Find(&conversations).Error
return conversations, err
}
func GetExistConversationUserIDList(ownerUserIDList []string, conversationID string) ([]string, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var resultArr []string
err = dbConn.Table("conversations").Where(" owner_user_id IN (?) and conversation_id=?", ownerUserIDList, conversationID).Pluck("owner_user_id", &resultArr).Error
if err != nil {
return nil, err
}
return resultArr, nil
}
func GetConversation(OwnerUserID, conversationID string) (db.Conversation, error) {
var conversation db.Conversation
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return conversation, err
}
err = dbConn.Table("conversations").Where("owner_user_id=? and conversation_id=?", OwnerUserID, conversationID).Take(&conversation).Error
return conversation, err
}
func GetConversations(OwnerUserID string, conversationIDs []string) ([]db.Conversation, error) {
var conversations []db.Conversation
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return conversations, err
}
err = dbConn.Model(&db.Conversation{}).Where("conversation_id IN (?) and owner_user_id=?", conversationIDs, OwnerUserID).Find(&conversations).Error
return conversations, err
}
func GetConversationsByConversationIDMultipleOwner(OwnerUserIDList []string, conversationID string) ([]db.Conversation, error) {
var conversations []db.Conversation
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return conversations, err
}
err = dbConn.Model(&db.Conversation{}).Where("owner_user_id IN (?) and conversation_id=?", OwnerUserIDList, conversationID).Find(&conversations).Error
return conversations, err
}
func UpdateColumnsConversations(ownerUserIDList []string, conversationID string, args map[string]interface{}) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
dbConn.LogMode(false)
return dbConn.Debug().Model(&db.Conversation{}).Where("owner_user_id IN (?) and conversation_id=?", ownerUserIDList, conversationID).Updates(args).Error
}
@@ -1,42 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
_ "github.com/jinzhu/gorm"
)
func GetRegister(account string) (*db.Register, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var r db.Register
return &r, dbConn.Table("registers").Where("account = ?",
account).Take(&r).Error
}
func SetPassword(account, password, ex, userID string) error {
r := db.Register{
Account: account,
Password: password,
Ex: ex,
UserID: userID,
}
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
return dbConn.Table("registers").Create(&r).Error
}
func ResetPassword(account, password string) error {
r := db.Register{
Password: password,
}
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
dbConn.LogMode(false)
if err != nil {
return err
}
return dbConn.Table("registers").Where("account = ?", account).Update(&r).Error
}
@@ -1,91 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
func InsertToFriend(toInsertFollow *db.Friend) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertFollow.CreateTime = time.Now()
err = dbConn.Table("friends").Create(toInsertFollow).Error
if err != nil {
return err
}
return nil
}
func GetFriendRelationshipFromFriend(OwnerUserID, FriendUserID string) (*db.Friend, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friend db.Friend
err = dbConn.Table("friends").Where("owner_user_id=? and friend_user_id=?", OwnerUserID, FriendUserID).Take(&friend).Error
if err != nil {
return nil, err
}
return &friend, err
}
func GetFriendListByUserID(OwnerUserID string) ([]db.Friend, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friends []db.Friend
var x db.Friend
x.OwnerUserID = OwnerUserID
err = dbConn.Table("friends").Where("owner_user_id=?", OwnerUserID).Find(&friends).Error
if err != nil {
return nil, err
}
return friends, nil
}
func GetFriendIDListByUserID(OwnerUserID string) ([]*string, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friendIDList []*string
err = dbConn.Table("friends").Select("friend_user_id").Where("owner_user_id=?", OwnerUserID).Find(&friendIDList).Error
if err != nil {
return nil, err
}
return friendIDList, nil
}
func UpdateFriendComment(OwnerUserID, FriendUserID, Remark string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("update friends set remark=? where owner_user_id=? and friend_user_id=?", Remark, OwnerUserID, FriendUserID).Error
return err
}
func DeleteSingleFriendInfo(OwnerUserID, FriendUserID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("friends").Where("owner_user_id=? and friend_user_id=?", OwnerUserID, FriendUserID).Delete(db.Friend{}).Error
return err
}
//type Friend struct {
// OwnerUserID string `gorm:"column:owner_user_id;primaryKey;"`
// FriendUserID string `gorm:"column:friend_user_id;primaryKey;"`
// Remark string `gorm:"column:remark"`
// CreateTime time.Time `gorm:"column:create_time"`
// AddSource int32 `gorm:"column:add_source"`
// OperatorUserID string `gorm:"column:operator_user_id"`
// Ex string `gorm:"column:ex"`
//}
@@ -1,112 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"Open_IM/pkg/utils"
"time"
)
//type FriendRequest struct {
// FromUserID string `gorm:"column:from_user_id;primaryKey;"`
// ToUserID string `gorm:"column:to_user_id;primaryKey;"`
// HandleResult int32 `gorm:"column:handle_result"`
// ReqMessage string `gorm:"column:req_message"`
// CreateTime time.Time `gorm:"column:create_time"`
// HandlerUserID string `gorm:"column:handler_user_id"`
// HandleMsg string `gorm:"column:handle_msg"`
// HandleTime time.Time `gorm:"column:handle_time"`
// Ex string `gorm:"column:ex"`
//}
// who apply to add me
func GetReceivedFriendsApplicationListByUserID(ToUserID string) ([]db.FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var usersInfo []db.FriendRequest
err = dbConn.Table("friend_requests").Where("to_user_id=?", ToUserID).Find(&usersInfo).Error
if err != nil {
return nil, err
}
return usersInfo, nil
}
//I apply to add somebody
func GetSendFriendApplicationListByUserID(FromUserID string) ([]db.FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var usersInfo []db.FriendRequest
err = dbConn.Table("friend_requests").Where("from_user_id=?", FromUserID).Find(&usersInfo).Error
if err != nil {
return nil, err
}
return usersInfo, nil
}
//FromUserId apply to add ToUserID
func GetFriendApplicationByBothUserID(FromUserID, ToUserID string) (*db.FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friendRequest db.FriendRequest
err = dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?", FromUserID, ToUserID).Take(&friendRequest).Error
if err != nil {
return nil, err
}
return &friendRequest, nil
}
func UpdateFriendApplication(friendRequest *db.FriendRequest) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
friendRequest.CreateTime = time.Now()
return dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?",
friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest).Error
}
func InsertFriendApplication(friendRequest *db.FriendRequest, args map[string]interface{}) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
if err = dbConn.Table("friend_requests").Create(friendRequest).Error; err == nil {
return nil
}
//t := dbConn.Debug().Table("friend_requests").Where("from_user_id = ? and to_user_id = ?", friendRequest.FromUserID, friendRequest.ToUserID).Select("*").Updates(*friendRequest)
//if t.RowsAffected == 0 {
// return utils.Wrap(errors.New("RowsAffected == 0"), "no update")
//}
//return utils.Wrap(t.Error, "")
friendRequest.CreateTime = time.Now()
args["create_time"] = friendRequest.CreateTime
u := dbConn.Model(friendRequest).Updates(args)
//u := dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?",
// friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest)
//u := dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?",
// friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest)
if u.RowsAffected != 0 {
return nil
}
if friendRequest.CreateTime.Unix() < 0 {
friendRequest.CreateTime = time.Now()
}
if friendRequest.HandleTime.Unix() < 0 {
friendRequest.HandleTime = utils.UnixSecondToTime(0)
}
err = dbConn.Table("friend_requests").Create(friendRequest).Error
if err != nil {
return err
}
return nil
}
@@ -1,316 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/utils"
"errors"
"fmt"
"time"
)
//type GroupMember struct {
// GroupID string `gorm:"column:group_id;primaryKey;"`
// UserID string `gorm:"column:user_id;primaryKey;"`
// NickName string `gorm:"column:nickname"`
// FaceUrl string `gorm:"user_group_face_url"`
// RoleLevel int32 `gorm:"column:role_level"`
// JoinTime time.Time `gorm:"column:join_time"`
// JoinSource int32 `gorm:"column:join_source"`
// OperatorUserID string `gorm:"column:operator_user_id"`
// Ex string `gorm:"column:ex"`
//}
func InsertIntoGroupMember(toInsertInfo db.GroupMember) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertInfo.JoinTime = time.Now()
if toInsertInfo.RoleLevel == 0 {
toInsertInfo.RoleLevel = constant.GroupOrdinaryUsers
}
toInsertInfo.MuteEndTime = time.Unix(int64(time.Now().Second()), 0)
err = dbConn.Table("group_members").Create(toInsertInfo).Error
if err != nil {
return err
}
return nil
}
func GetGroupMemberListByUserID(userID string) ([]db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []db.GroupMember
err = dbConn.Table("group_members").Where("user_id=?", userID).Find(&groupMemberList).Error
//err = dbConn.Table("group_members").Where("user_id=?", userID).Take(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func GetGroupMemberListByGroupID(groupID string) ([]db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []db.GroupMember
err = dbConn.Table("group_members").Where("group_id=?", groupID).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func GetGroupMemberIDListByGroupID(groupID string) ([]string, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
dbConn.LogMode(false)
var groupMembers []db.GroupMember
err = dbConn.Table("group_members").Select("user_id").Where("group_id=?", groupID).Find(&groupMembers).Error
if err != nil {
return nil, err
}
var groupMemberIDList []string
for _, v := range groupMembers {
groupMemberIDList = append(groupMemberIDList, v.UserID)
}
return groupMemberIDList, nil
}
func GetGroupMemberListByGroupIDAndRoleLevel(groupID string, roleLevel int32) ([]db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []db.GroupMember
err = dbConn.Table("group_members").Where("group_id=? and role_level=?", groupID, roleLevel).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func GetGroupMemberInfoByGroupIDAndUserID(groupID, userID string) (*db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMember db.GroupMember
err = dbConn.Table("group_members").Where("group_id=? and user_id=? ", groupID, userID).Limit(1).Take(&groupMember).Error
if err != nil {
return nil, err
}
return &groupMember, nil
}
func DeleteGroupMemberByGroupIDAndUserID(groupID, userID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("group_members").Where("group_id=? and user_id=? ", groupID, userID).Delete(db.GroupMember{}).Error
if err != nil {
return err
}
return nil
}
func DeleteGroupMemberByGroupID(groupID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("group_members").Where("group_id=? ", groupID).Delete(db.GroupMember{}).Error
if err != nil {
return err
}
return nil
}
func UpdateGroupMemberInfo(groupMemberInfo db.GroupMember) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("group_members").Where("group_id=? and user_id=?", groupMemberInfo.GroupID, groupMemberInfo.UserID).Update(&groupMemberInfo).Error
if err != nil {
return err
}
return nil
}
func GetOwnerManagerByGroupID(groupID string) ([]db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []db.GroupMember
err = dbConn.Table("group_members").Where("group_id=? and role_level>?", groupID, constant.GroupOrdinaryUsers).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func GetGroupMemberNumByGroupID(groupID string) (uint32, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return 0, utils.Wrap(err, "DefaultGormDB failed")
}
var number uint32
err = dbConn.Table("group_members").Where("group_id=?", groupID).Count(&number).Error
if err != nil {
return 0, utils.Wrap(err, "")
}
return number, nil
}
func GetGroupOwnerInfoByGroupID(groupID string) (*db.GroupMember, error) {
omList, err := GetOwnerManagerByGroupID(groupID)
if err != nil {
return nil, err
}
for _, v := range omList {
if v.RoleLevel == constant.GroupOwner {
return &v, nil
}
}
return nil, utils.Wrap(errors.New("no owner"), "")
}
func IsExistGroupMember(groupID, userID string) bool {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return false
}
var number int32
err = dbConn.Table("group_members").Where("group_id = ? and user_id = ?", groupID, userID).Count(&number).Error
if err != nil {
return false
}
if number != 1 {
return false
}
return true
}
func RemoveGroupMember(groupID string, UserID string) error {
return DeleteGroupMemberByGroupIDAndUserID(groupID, UserID)
}
func GetMemberInfoByID(groupID string, userID string) (*db.GroupMember, error) {
return GetGroupMemberInfoByGroupIDAndUserID(groupID, userID)
}
func GetGroupMemberByGroupID(groupID string, filter int32, begin int32, maxNumber int32) ([]db.GroupMember, error) {
var memberList []db.GroupMember
var err error
if filter >= 0 {
memberList, err = GetGroupMemberListByGroupIDAndRoleLevel(groupID, filter) //sorted by join time
} else {
memberList, err = GetGroupMemberListByGroupID(groupID)
}
if err != nil {
return nil, err
}
if begin >= int32(len(memberList)) {
return nil, nil
}
var end int32
if begin+int32(maxNumber) < int32(len(memberList)) {
end = begin + maxNumber
} else {
end = int32(len(memberList))
}
return memberList[begin:end], nil
}
func GetJoinedGroupIDListByUserID(userID string) ([]string, error) {
memberList, err := GetGroupMemberListByUserID(userID)
if err != nil {
return nil, err
}
var groupIDList []string
for _, v := range memberList {
groupIDList = append(groupIDList, v.GroupID)
}
return groupIDList, nil
}
func IsGroupOwnerAdmin(groupID, UserID string) bool {
groupMemberList, err := GetOwnerManagerByGroupID(groupID)
if err != nil {
return false
}
for _, v := range groupMemberList {
if v.UserID == UserID && v.RoleLevel > constant.GroupOrdinaryUsers {
return true
}
}
return false
}
func GetGroupMembersByGroupIdCMS(groupId string, userName string, showNumber, pageNumber int32) ([]db.GroupMember, error) {
var groupMembers []db.GroupMember
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return groupMembers, err
}
err = dbConn.Table("group_members").Where("group_id=?", groupId).Where(fmt.Sprintf(" nickname like '%%%s%%' ", userName)).Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groupMembers).Error
if err != nil {
return nil, err
}
return groupMembers, nil
}
func GetGroupMembersCount(groupId, userName string) (int32, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
var count int32
if err != nil {
return count, err
}
dbConn.LogMode(false)
if err := dbConn.Table("group_members").Where("group_id=?", groupId).Where(fmt.Sprintf(" nickname like '%%%s%%' ", userName)).Count(&count).Error; err != nil {
return count, err
}
return count, nil
}
func UpdateGroupMemberInfoDefaultZero(groupMemberInfo db.GroupMember, args map[string]interface{}) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
return dbConn.Model(groupMemberInfo).Updates(args).Error
}
//
//func SelectGroupList(groupID string) ([]string, error) {
// var groupUserID string
// var groupList []string
// dbConn, err := db.DB.MysqlDB.DefaultGormDB()
// if err != nil {
// return groupList, err
// }
//
// rows, err := dbConn.Model(&GroupMember{}).Where("group_id = ?", groupID).Select("user_id").Rows()
// if err != nil {
// return groupList, err
// }
// defer rows.Close()
// for rows.Next() {
// rows.Scan(&groupUserID)
// groupList = append(groupList, groupUserID)
// }
// return groupList, nil
//}
@@ -1,225 +0,0 @@
package im_mysql_model
import (
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/utils"
"errors"
"fmt"
"github.com/jinzhu/gorm"
"time"
)
//type Group struct {
// GroupID string `gorm:"column:group_id;primaryKey;"`
// GroupName string `gorm:"column:name"`
// Introduction string `gorm:"column:introduction"`
// Notification string `gorm:"column:notification"`
// FaceUrl string `gorm:"column:face_url"`
// CreateTime time.Time `gorm:"column:create_time"`
// Status int32 `gorm:"column:status"`
// CreatorUserID string `gorm:"column:creator_user_id"`
// GroupType int32 `gorm:"column:group_type"`
// Ex string `gorm:"column:ex"`
//}
func InsertIntoGroup(groupInfo db.Group) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
if groupInfo.GroupName == "" {
groupInfo.GroupName = "Group Chat"
}
groupInfo.CreateTime = time.Now()
err = dbConn.Table("groups").Create(groupInfo).Error
if err != nil {
return err
}
return nil
}
func GetGroupInfoByGroupID(groupId string) (*db.Group, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, utils.Wrap(err, "")
}
var groupInfo db.Group
err = dbConn.Table("groups").Where("group_id=?", groupId).Take(&groupInfo).Error
if err != nil {
return nil, err
}
return &groupInfo, nil
}
func SetGroupInfo(groupInfo db.Group) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("groups").Where("group_id=?", groupInfo.GroupID).Update(&groupInfo).Error
return err
}
func GetGroupsByName(groupName string, pageNumber, showNumber int32) ([]db.Group, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
var groups []db.Group
if err != nil {
return groups, err
}
err = dbConn.Table("groups").Where(fmt.Sprintf(" name like '%%%s%%' ", groupName)).Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groups).Error
return groups, err
}
func GetGroups(pageNumber, showNumber int) ([]db.Group, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
var groups []db.Group
if err != nil {
return groups, err
}
if err = dbConn.Table("groups").Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groups).Error; err != nil {
return groups, err
}
return groups, nil
}
func OperateGroupStatus(groupId string, groupStatus int32) error {
group := db.Group{
GroupID: groupId,
Status: groupStatus,
}
if err := SetGroupInfo(group); err != nil {
return err
}
return nil
}
func DeleteGroup(groupId string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
var group db.Group
var groupMembers []db.GroupMember
if err := dbConn.Table("groups").Where("group_id=?", groupId).Delete(&group).Error; err != nil {
return err
}
if err := dbConn.Table("group_members").Where("group_id=?", groupId).Delete(groupMembers).Error; err != nil {
return err
}
return nil
}
func OperateGroupRole(userId, groupId string, roleLevel int32) (string, string, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return "", "", err
}
groupMember := db.GroupMember{
UserID: userId,
GroupID: groupId,
}
updateInfo := db.GroupMember{
RoleLevel: roleLevel,
}
groupMaster := db.GroupMember{}
switch roleLevel {
case constant.GroupOwner:
err = dbConn.Transaction(func(tx *gorm.DB) error {
result := dbConn.Table("group_members").Where("group_id = ? and role_level = ?", groupId, constant.GroupOwner).First(&groupMaster).Update(&db.GroupMember{
RoleLevel: constant.GroupOrdinaryUsers,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId))
}
result = dbConn.Table("group_members").First(&groupMember).Update(updateInfo)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId))
}
return nil
})
case constant.GroupOrdinaryUsers:
err = dbConn.Transaction(func(tx *gorm.DB) error {
result := dbConn.Table("group_members").Where("group_id = ? and role_level = ?", groupId, constant.GroupOwner).First(&groupMaster)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId))
}
if groupMaster.UserID == userId {
return errors.New(fmt.Sprintf("user %s is master of %s, cant set to ordinary user", userId, groupId))
} else {
result = dbConn.Table("group_members").Find(&groupMember).Update(updateInfo)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId))
}
}
return nil
})
}
return "", "", nil
}
func GetGroupsCountNum(group db.Group) (int32, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return 0, err
}
var count int32
if err := dbConn.Table("groups").Where(fmt.Sprintf(" name like '%%%s%%' ", group.GroupName)).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
func GetGroupById(groupId string) (db.Group, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
group := db.Group{
GroupID: groupId,
}
if err != nil {
return group, err
}
if err := dbConn.Table("groups").Find(&group).Error; err != nil {
return group, err
}
return group, nil
}
func GetGroupMaster(groupId string) (db.GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
groupMember := db.GroupMember{}
if err != nil {
return groupMember, err
}
if err := dbConn.Table("group_members").Where("role_level=? and group_id=?", constant.GroupOwner, groupId).Find(&groupMember).Error; err != nil {
return groupMember, err
}
return groupMember, nil
}
func UpdateGroupInfoDefaultZero(groupID string, args map[string]interface{}) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
return dbConn.Table("groups").Where("group_id = ? ", groupID).Update(args).Error
}

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