@ -2,282 +2,216 @@ package cache
import (
import (
"context"
"context"
"errors"
"math/big"
"strings"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/relation"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
relationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/OpenIMSDK/Open-IM-Server/pkg/utils"
"github.com/dtm-labs/rockscache"
"github.com/dtm-labs/rockscache"
"github.com/go-redis/redis/v8"
"github.com/go-redis/redis/v8"
"time"
)
)
const (
const (
conversationKey = "CONVERSATION:"
conversationKey = "CONVERSATION:"
conversationIDsKey = "CONVERSATION_IDS:"
conversationIDsKey = "CONVERSATION_IDS:"
recvMsgOptKey = "RECV_MSG_OPT:"
recvMsgOptKey = "RECV_MSG_OPT:"
superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
conversationExpireTime = time . Second * 60 * 60 * 12
superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
)
type FuncDB func ( ) ( string , error )
conversationExpireTime = time . Second * 60 * 60 * 12
)
// arg fn will exec when no data in cache
// arg fn will exec when no data in cache
type ConversationCache interface {
type ConversationCache interface {
metaCache
NewCache ( ) ConversationCache
// get user's conversationIDs from cache
// get user's conversationIDs from cache
GetUserConversationIDs ( ctx context . Context , userID string , fn FuncDB ) ( [ ] string , error )
GetUserConversationIDs ( ctx context . Context , ownerUserID string ) ( [ ] string , error )
// del user's conversationIDs from cache, call when a user add or reduce a conversation
DelConversationIDs ( userIDs [ ] string ) ConversationCache
DelUserConversationIDs ( ctx context . Context , userID string ) error
DelUsersConversationIDs ( ctx context . Context , userIDList [ ] string ) error
// get one conversation from cache
// get one conversation from cache
GetConversation ( ctx context . Context , ownerUserID , conversationID string , fn FuncDB ) ( * relationTb . ConversationModel , error )
GetConversation ( ctx context . Context , ownerUserID , conversationID string ) ( * relationTb . ConversationModel , error )
DelConvsersations ( ownerUserID string , conversationIDs [ ] string ) ConversationCache
DelUsersConversation ( ownerUserIDs [ ] string , conversationID string ) ConversationCache
// get one conversation from cache
// get one conversation from cache
GetConversations ( ctx context . Context , ownerUserID string , conversationIDs [ ] string , fn FuncDB ) ( [ ] * relationTb . ConversationModel , error )
GetConversations ( ctx context . Context , ownerUserID string , conversationIDs [ ] string ) ( [ ] * relationTb . ConversationModel , error )
// get one user's all conversations from cache
// get one user's all conversations from cache
GetUserAllConversations ( ctx context . Context , ownerUserID string , fn FuncDB ) ( [ ] * relationTb . ConversationModel , error )
GetUserAllConversations ( ctx context . Context , ownerUserID string ) ( [ ] * relationTb . ConversationModel , error )
// del one conversation from cache, call when one user's conversation Info changed
DelConversation ( ctx context . Context , ownerUserID , conversationID string ) error
DelUserConversations ( ctx context . Context , ownerUserID string , conversationIDList [ ] string ) error
DelUsersConversation ( ctx context . Context , ownerUserIDList [ ] string , conversationID string ) error
// get user conversation recv msg from cache
// get user conversation recv msg from cache
GetUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string , fn func ( ctx context . Context , ownerUserID , conversationID string ) ( opt int , err error ) ) ( opt int , err error )
GetUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string ) ( opt int , err error )
// del user recv msg opt from cache, call when user's conversation recv msg opt changed
DelUserRecvMsgOpt ( ownerUserID , conversationID string ) ConversationCache
DelUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string ) error
// get one super group recv msg but do not notification userID list
// get one super group recv msg but do not notification userID list
GetSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string , fn func ( ctx context . Context , groupID string ) ( userIDs [ ] string , err error ) ) ( userIDs [ ] string , err error )
GetSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string ) ( userIDs [ ] string , err error )
// del one super group recv msg but do not notification userID list, call it when this list changed
// get one super group recv msg but do not notification userID list hash
DelSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string ) error
GetSuperGroupRecvMsgNotNotifyUserIDsHash ( ctx context . Context , groupID string ) ( hash uint64 , err error )
//GetSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string) (hash uint32, err error)
//DelSuperGroupRecvMsgNotNotifyUserIDsHash(ctx context.Context, groupID string)
}
}
func NewConversationRedis ( rdb redis . UniversalClient , opts rockscache . Options ) ConversationCache {
func NewConversationRedis ( rdb redis . UniversalClient , opts rockscache . Options , db relationTb . ConversationModelInterface ) ConversationCache {
return & ConversationRedis { rcClient : rockscache . NewClient ( rdb , opts ) }
rcClient := rockscache . NewClient ( rdb , opts )
return & ConversationRedisCache { rcClient : rcClient , metaCache : NewMetaCacheRedis ( rcClient ) , conversationDB : db , expireTime : conversationExpireTime }
}
}
type ConversationRedis struct {
type ConversationRedisCache struct {
rcClient * rockscache . Client
metaCache
expireTime time . Duration
rcClient * rockscache . Client
conversationDB relationTb . ConversationModelInterface
expireTime time . Duration
}
}
func ( c * ConversationRedis ) GetUserConversationIDs ( ctx context . Context , userID string , fn FuncDB ) ( [ ] string , error ) {
func NewNewConversationRedis ( rdb redis . UniversalClient , conversationDB * relation . ConversationGorm , options rockscache . Options ) ConversationCache {
return nil , nil
rcClient := rockscache . NewClient ( rdb , options )
return & ConversationRedisCache { rcClient : rcClient , metaCache : NewMetaCacheRedis ( rcClient ) , conversationDB : conversationDB , expireTime : conversationExpireTime }
}
}
func ( c * ConversationRedis ) GetConversation ( ctx context . Context , ownerUserID , conversationID string , fn FuncDB ) ( * relationTb . ConversationModel , error ) {
func ( c * ConversationRedisCache ) NewCache ( ) ConversationCache {
//TODO implement me
return & ConversationRedisCache { rcClient : c . rcClient , metaCache : c . metaCache , conversationDB : c . conversationDB , expireTime : c . expireTime }
panic ( "implement me" )
}
}
func ( c * ConversationRedis ) GetConversations ( ctx context . Context , ownerUserID string , conversationIDs [ ] string , fn FuncDB ) ( [ ] * relationTb . ConversationModel , error ) {
func ( c * ConversationRedisCache ) getConversationKey ( ownerUserID , conversationID string ) string {
//TODO implement me
return conversationKey + ownerUserID + ":" + conversationID
panic ( "implement me" )
}
func ( c * ConversationRedis ) GetUserAllConversations ( ctx context . Context , ownerUserID string , fn FuncDB ) ( [ ] * relationTb . ConversationModel , error ) {
//TODO implement me
panic ( "implement me" )
}
}
func ( c * ConversationRedis ) DelUserConversations ( ctx context . Context , ownerUserID string , conversationIDList [ ] string ) error {
func ( c * ConversationRedisCache ) getConversationIDsKey ( ownerUserID string ) string {
//TODO implement me
return conversationIDsKey + ownerUserID
panic ( "implement me" )
}
}
func ( c * ConversationRedis ) GetUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string , fn func ( ctx context . Context , ownerUserID string , conversationID string ) ( opt int , err error ) ) ( opt int , err error ) {
func ( c * ConversationRedisCache ) getSuperGroupRecvNotNotifyUserIDsKey ( groupID string ) string {
//TODO implement me
return superGroupRecvMsgNotNotifyUserIDsKey + groupID
panic ( "implement me" )
}
}
func ( c * ConversationRedis ) GetSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string , fn func ( ctx context . Context , groupID string ) ( userIDs [ ] string , err error ) ) ( userIDs [ ] string , err error ) {
func ( c * ConversationRedisCache ) getRecvMsgOptKey ( ownerUserID , conversationID string ) string {
//TODO implement me
return recvMsgOptKey + ownerUserID + ":" + conversationID
panic ( "implement me" )
}
}
func ( c * ConversationRedis ) DelUsersConversationIDs ( ctx context . Context , userIDList [ ] string ) error {
func ( c * ConversationRedis Cache) getSuperGroupRecvNotNotifyUserIDsHashKey ( groupID string ) string {
panic ( "implement me" )
return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID
}
}
func ( c * ConversationRedis ) DelUsersConversation ( ctx context . Context , ownerUserIDList [ ] string , conversationID string ) error {
func ( c * ConversationRedisCache ) GetUserConversationIDs ( ctx context . Context , ownerUserID string ) ( [ ] string , error ) {
panic ( "implement me" )
return getCache ( ctx , c . rcClient , c . getConversationIDsKey ( ownerUserID ) , c . expireTime , func ( ctx context . Context ) ( [ ] string , error ) {
return c . conversationDB . FindUserIDAllConversationID ( ctx , ownerUserID )
} )
}
}
func NewNewConversationRedis ( rdb redis . UniversalClient , conversationDB * relation . ConversationGorm , options rockscache . Options ) * ConversationRedis {
func ( c * ConversationRedisCache ) DelConversationIDs ( userIDs [ ] string ) ConversationCache {
return & ConversationRedis { rcClient : rockscache . NewClient ( rdb , options ) }
var keys [ ] string
for _ , userID := range userIDs {
keys = append ( keys , c . getConversationIDsKey ( userID ) )
}
cache := c . NewCache ( )
cache . AddKeys ( keys ... )
return cache
}
}
func ( c * ConversationRedis ) getConversationKey ( ownerUserID , conversationID string ) string {
func ( c * ConversationRedisCache ) GetConversation ( ctx context . Context , ownerUserID , conversationID string ) ( * relationTb . ConversationModel , error ) {
return conversationKey + ownerUserID + ":" + conversationID
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 * ConversationRedis ) getConversationIDsKey ( ownerUserID string ) string {
func ( c * ConversationRedisCache ) DelConvsersations ( ownerUserID string , convsersationIDs [ ] string ) ConversationCache {
return conversationIDsKey + ownerUserID
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 * ConversationRedis ) getRecvMsgOptKey ( ownerUserID , conversationID string ) string {
func ( c * ConversationRedisCache ) GetUserAllConversations ( ctx context . Context , ownerUserID string ) ( [ ] * relationTb . ConversationModel , error ) {
return recvMsgOptKey + ownerUserID + ":" + conversationID
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 * ConversationRedis ) getSuperGroupRecvNotNotifyUserIDsKey ( groupID string ) string {
func ( c * ConversationRedisCache ) DelUserConversations ( ctx context . Context , ownerUserID string , conversationIDs [ ] string ) ConversationCache {
return superGroupRecvMsgNotNotifyUserIDsKey + groupID
var keys [ ] string
for _ , conversationID := range conversationIDs {
keys = append ( keys , c . getConversationKey ( ownerUserID , conversationID ) )
}
cache := c . NewCache ( )
cache . AddKeys ( keys ... )
return cache
}
}
//func (c *ConversationRedis) GetUserConversationIDs(ctx context.Context, ownerUserID string) (conversationIDs []string, err error) {
func ( c * ConversationRedisCache ) GetUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string ) ( opt int , err error ) {
// //getConversationIDs := func() (string, error) {
return getCache ( ctx , c . rcClient , c . getRecvMsgOptKey ( ownerUserID , conversationID ) , c . expireTime , func ( ctx context . Context ) ( opt int , err error ) {
// // conversationIDs, err := relation.GetConversationIDsByUserID(ownerUserID)
return c . conversationDB . GetUserRecvMsgOpt ( ctx , ownerUserID , conversationID )
// // if err != nil {
// // return "", err
// // }
// // bytes, err := json.Marshal(conversationIDs)
// // if err != nil {
// // return "", utils.Wrap(err, "")
// // }
// // return string(bytes), nil
// //}
// //defer func() {
// // mcontext.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "conversationIDs", conversationIDs)
// //}()
// //conversationIDsStr, err := c.rcClient.Fetch(c.getConversationIDsKey(ownerUserID), time.Second*30*60, getConversationIDs)
// //err = json.Unmarshal([]byte(conversationIDsStr), &conversationIDs)
// //if err != nil {
// // return nil, utils.Wrap(err, "")
// //}
// //return conversationIDs, nil
// return GetCache(ctx, c.rcClient, c.getConversationIDsKey(ownerUserID), conversationExpireTime, func(ctx context.Context) ([]string, error) {
// panic("implement me")
// })
//}
func ( c * ConversationRedis ) GetUserConversationIDs1 ( ctx context . Context , ownerUserID string ) ( conversationIDs [ ] string , err error ) {
//getConversationIDs := func() (string, error) {
// conversationIDs, err := relation.GetConversationIDsByUserID(ownerUserID)
// if err != nil {
// return "", err
// }
// bytes, err := json.Marshal(conversationIDs)
// if err != nil {
// return "", utils.Wrap(err, "")
// }
// return string(bytes), nil
//}
//defer func() {
// mcontext.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "conversationIDs", conversationIDs)
//}()
//conversationIDsStr, err := c.rcClient.Fetch(c.getConversationIDsKey(ownerUserID), time.Second*30*60, getConversationIDs)
//err = json.Unmarshal([]byte(conversationIDsStr), &conversationIDs)
//if err != nil {
// return nil, utils.Wrap(err, "")
//}
//return conversationIDs, nil
//return GetCache1[[]string](c.rcClient, c.getConversationIDsKey(ownerUserID), conversationExpireTime, fn)
return GetCache ( ctx , c . rcClient , c . getConversationIDsKey ( ownerUserID ) , conversationExpireTime , func ( ctx context . Context ) ( [ ] string , error ) {
panic ( "" )
} )
} )
}
}
//func GetCache1[T any](rcClient *rockscache.Client, key string, expire time.Duration, fn func() (any, error)) (T, error) {
func ( c * ConversationRedisCache ) GetSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string ) ( userIDs [ ] string , err error ) {
// v, err := rcClient.Fetch(key, expire, func() (string, error) {
return getCache ( ctx , c . rcClient , c . getSuperGroupRecvNotNotifyUserIDsKey ( groupID ) , c . expireTime , func ( ctx context . Context ) ( userIDs [ ] string , err error ) {
// v, err := fn()
return c . conversationDB . FindSuperGroupRecvMsgNotNotifyUserIDs ( ctx , groupID )
// if err != nil {
} )
// return "", err
// }
// bs, err := json.Marshal(v)
// if err != nil {
// return "", utils.Wrap(err, "")
// }
// return string(bs), nil
// })
// var t T
// if err != nil {
// return t, err
// }
// err = json.Unmarshal([]byte(v), &t)
// if err != nil {
// return t, utils.Wrap(err, "")
// }
// return t, nil
//}
func ( c * ConversationRedis ) DelUserConversationIDs ( ctx context . Context , ownerUserID string ) ( err error ) {
return utils . Wrap ( c . rcClient . TagAsDeleted ( c . getConversationIDsKey ( ownerUserID ) ) , "DelUserConversationIDs err" )
}
}
//func (c *ConversationRedis) GetConversation(ctx context.Context, ownerUserID, conversationID string) (conversation *relationTb.ConversationModel, err error) {
func ( c * ConversationRedisCache ) DelUsersConversation ( ownerUserIDs [ ] string , conversationID string ) ConversationCache {
// return GetCache(ctx, c.rcClient, c.getConversationKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (*relationTb.ConversationModel, error) {
var keys [ ] string
// panic("implement me")
for _ , ownerUserID := range ownerUserIDs {
// })
keys = append ( keys , c . getConversationKey ( ownerUserID , conversationID ) )
//}
}
cache := c . NewCache ( )
func ( c * ConversationRedis ) DelConversation ( ctx context . Context , ownerUserID , conversationID string ) ( err error ) {
cache . AddKeys ( keys ... )
return utils. Wrap ( c . rcClient . TagAsDeleted ( c . getConversationKey ( ownerUserID , conversationID ) ) , "DelConversation err" )
return cache
}
}
//func (c *ConversationRedis) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) (conversations []relationTb.ConversationModel, err error) {
func ( c * ConversationRedisCache ) DelUserRecvMsgOpt ( ownerUserID , conversationID string ) ConversationCache {
// defer func() {
cache := c . NewCache ( )
// mcontext.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "conversationIDs", conversationIDs, "conversations", conversations)
cache . AddKeys ( c . getRecvMsgOptKey ( ownerUserID , conversationID ) )
// }()
return cache
// for _, conversationID := range conversationIDs {
// conversation, err := c.GetConversation(ctx, ownerUserID, conversationID)
// if err != nil {
// return nil, err
// }
// conversations = append(conversations, *conversation)
// }
// return conversations, nil
//}
//func (c *ConversationRedis) GetUserAllConversations(ctx context.Context, ownerUserID string) (conversations []relationTb.ConversationModel, err error) {
// defer func() {
// mcontext.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "conversations", conversations)
// }()
// IDs, err := c.GetUserConversationIDs(ctx, ownerUserID)
// if err != nil {
// return nil, err
// }
// var conversationIDs []relationTb.ConversationModel
// for _, conversationID := range IDs {
// conversation, err := c.GetConversation(ctx, ownerUserID, conversationID)
// if err != nil {
// return nil, err
// }
// conversationIDs = append(conversationIDs, *conversation)
// }
// return conversationIDs, nil
//}
//func (c *ConversationRedis) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) {
// //getConversation := func() (string, error) {
// // conversation, err := relation.GetConversation(ownerUserID, conversationID)
// // if err != nil {
// // return "", err
// // }
// // return strconv.Itoa(int(conversation.RecvMsgOpt)), nil
// //}
// //defer func() {
// // mcontext.SetCtxDebug(ctx, utils.GetFuncName(1), err, "ownerUserID", ownerUserID, "conversationID", conversationID, "opt", opt)
// //}()
// //optStr, err := c.rcClient.Fetch(c.getConversationKey(ownerUserID, conversationID), c.expireTime, getConversation)
// //if err != nil {
// // return 0, err
// //}
// //return strconv.Atoi(optStr)
// // panic("implement me")
// return GetCache(ctx, c.rcClient, c.getConversationKey(ownerUserID, conversationID), c.expireTime, func(ctx context.Context) (int, error) {
// panic("implement me")
// })
//}
func ( c * ConversationRedis ) DelUserRecvMsgOpt ( ctx context . Context , ownerUserID , conversationID string ) error {
return utils . Wrap ( c . rcClient . TagAsDeleted ( c . getConversationKey ( ownerUserID , conversationID ) ) , "DelUserRecvMsgOpt failed" )
}
}
func ( c * ConversationRedis ) DelSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string ) ( err error ) {
func ( c * ConversationRedisCache ) DelSuperGroupRecvMsgNotNotifyUserIDs ( ctx context . Context , groupID string ) ConversationCache {
panic ( "implement me" )
cache := c . NewCache ( )
cache . AddKeys ( c . getSuperGroupRecvNotNotifyUserIDsKey ( groupID ) )
return cache
}
}
func ( c * ConversationRedis ) GetSuperGroupRecvMsgNotNotifyUserIDsHash ( ctx context . Context , groupID string ) ( hash uint32 , err error ) {
func ( c * ConversationRedisCache ) GetSuperGroupRecvMsgNotNotifyUserIDsHash ( ctx context . Context , groupID string ) ( hash uint64 , err error ) {
panic ( "implement me" )
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 * ConversationRedis ) DelSuperGroupRecvMsgNotNotifyUserIDsHash ( ctx context . Context , groupID string ) {
func ( c * ConversationRedisCache ) DelSuperGroupRecvMsgNotNotifyUserIDsHash ( ctx context . Context , groupID string ) {
panic ( "implement me" )
panic ( "implement me" )
}
}