mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-07-06 03:31:08 +08:00
会话静音
This commit is contained in:
parent
1a3d7020ad
commit
8cd3dff8f8
@ -1,14 +1,14 @@
|
|||||||
# Cursor 代码索引忽略(语法与 .gitignore 相同)
|
# Cursor 代码索引忽略(语法与 .gitignore 相同)
|
||||||
# 与根目录 .gitignore 对齐;未列出的规则仍以 .gitignore 为准(Git 不索引的路径 Cursor 通常也不关心)
|
# 与根目录 .gitignore 对齐;以下为补充规则,减少生成物/文档噪音,保留业务源码与 .proto
|
||||||
|
|
||||||
### OpenIM(与 .gitignore 一致)###
|
### OpenIM(与 .gitignore 一致)###
|
||||||
logs
|
logs/
|
||||||
.devcontainer
|
.devcontainer/
|
||||||
components
|
components/
|
||||||
out-test
|
out-test/
|
||||||
Dockerfile.cross
|
Dockerfile.cross
|
||||||
|
|
||||||
### macOS / 本地工具(不入索引)###
|
### macOS / 本地工具 ###
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
|
|
||||||
@ -17,26 +17,51 @@ tmp/
|
|||||||
bin/
|
bin/
|
||||||
output/
|
output/
|
||||||
_output/
|
_output/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
deployments/charts/generated-configs/
|
deployments/charts/generated-configs/
|
||||||
|
|
||||||
### 配置与密钥(勿入索引)###
|
### 配置与密钥(勿入索引)###
|
||||||
.env
|
.env
|
||||||
config/config.yaml
|
config/config.yaml
|
||||||
config/notification.yaml
|
config/notification.yaml
|
||||||
|
start-config.yml
|
||||||
|
|
||||||
### 部署生成物 ###
|
### 部署生成物 ###
|
||||||
deployments/openim-server/charts
|
deployments/openim-server/charts/
|
||||||
|
|
||||||
### 本地笔记 ###
|
### 本地笔记 ###
|
||||||
.idea.md
|
.idea.md
|
||||||
.todo.md
|
.todo.md
|
||||||
.note.md
|
.note.md
|
||||||
|
|
||||||
|
### 生成代码(以 .proto 为准,勿重复索引)###
|
||||||
|
protocol/**/*.pb.go
|
||||||
|
protocol/**/*_grpc.pb.go
|
||||||
|
|
||||||
|
### 文档与资源(保留 docs/contrib、根 README;忽略多语言 readme 与静态资源)###
|
||||||
|
docs/readme/
|
||||||
|
docs/.generated_docs
|
||||||
|
docs/contributing/
|
||||||
|
assets/
|
||||||
|
virgil_chat_server_design.md
|
||||||
|
docs/virgil-e2ee-*.md
|
||||||
|
|
||||||
|
### 测试与脚本输出 ###
|
||||||
|
test/e2e/output/
|
||||||
|
scripts/**/*.log
|
||||||
|
|
||||||
### 通用备份与临时文件 ###
|
### 通用备份与临时文件 ###
|
||||||
*.bak
|
*.bak
|
||||||
|
*.gho
|
||||||
|
*.ori
|
||||||
|
*.orig
|
||||||
*.tmp
|
*.tmp
|
||||||
*~
|
*~
|
||||||
dist/
|
*.BACKUP.*
|
||||||
|
*.BASE.*
|
||||||
|
*.LOCAL.*
|
||||||
|
*.REMOTE.*
|
||||||
|
|
||||||
### VS Code(除团队共享配置外)###
|
### VS Code(除团队共享配置外)###
|
||||||
.vscode/*
|
.vscode/*
|
||||||
@ -44,6 +69,7 @@ dist/
|
|||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
### Go ###
|
### Go ###
|
||||||
*.exe
|
*.exe
|
||||||
@ -54,13 +80,19 @@ dist/
|
|||||||
*.test
|
*.test
|
||||||
*.out
|
*.out
|
||||||
vendor/
|
vendor/
|
||||||
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
go.sum
|
||||||
|
|
||||||
### JetBrains / IDE ###
|
### JetBrains / IDE ###
|
||||||
.idea/
|
.idea/
|
||||||
out/
|
out/
|
||||||
|
|
||||||
### Tags ###
|
### Git / CI(低价值索引)###
|
||||||
|
.git/
|
||||||
|
.github/
|
||||||
|
|
||||||
|
### Tags / 索引工具 ###
|
||||||
TAGS
|
TAGS
|
||||||
tags
|
tags
|
||||||
gtags.files
|
gtags.files
|
||||||
@ -70,3 +102,5 @@ GPATH
|
|||||||
GSYMS
|
GSYMS
|
||||||
cscope.files
|
cscope.files
|
||||||
cscope.out
|
cscope.out
|
||||||
|
cscope.in.out
|
||||||
|
cscope.po.out
|
||||||
|
|||||||
@ -71,3 +71,7 @@ func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) {
|
|||||||
func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
|
func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
|
||||||
a2r.Call(c, conversation.ConversationClient.GetPinnedConversationIDs, o.Client)
|
a2r.Call(c, conversation.ConversationClient.GetPinnedConversationIDs, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ConversationApi) SetMute(c *gin.Context) {
|
||||||
|
a2r.Call(c, conversation.ConversationClient.SetConversationMute, o.Client)
|
||||||
|
}
|
||||||
|
|||||||
@ -131,13 +131,6 @@ func (o *FriendApi) AddOnewayFriend(c *gin.Context) {
|
|||||||
a2r.Call(c, relation.FriendClient.AddOnewayFriend, o.Client)
|
a2r.Call(c, relation.FriendClient.AddOnewayFriend, o.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *FriendApi) SetMute(c *gin.Context) {
|
|
||||||
a2r.Call(c, relation.FriendClient.SetMute, o.Client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *FriendApi) GetMute(c *gin.Context) {
|
|
||||||
a2r.Call(c, relation.FriendClient.GetMute, o.Client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *FriendApi) PinFriend(c *gin.Context) {
|
func (o *FriendApi) PinFriend(c *gin.Context) {
|
||||||
a2r.Call(c, relation.FriendClient.PinFriend, o.Client)
|
a2r.Call(c, relation.FriendClient.PinFriend, o.Client)
|
||||||
|
|||||||
@ -222,8 +222,6 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
|||||||
friendRouterGroup.POST("/get_self_unhandled_apply_count", f.GetSelfUnhandledApplyCount)
|
friendRouterGroup.POST("/get_self_unhandled_apply_count", f.GetSelfUnhandledApplyCount)
|
||||||
friendRouterGroup.POST("/get_pinned_friend_ids", f.GetPinnedFriendIDs)
|
friendRouterGroup.POST("/get_pinned_friend_ids", f.GetPinnedFriendIDs)
|
||||||
friendRouterGroup.POST("/add_oneway_friend", f.AddOnewayFriend)
|
friendRouterGroup.POST("/add_oneway_friend", f.AddOnewayFriend)
|
||||||
friendRouterGroup.POST("/set_mute", f.SetMute)
|
|
||||||
friendRouterGroup.POST("/get_mute", f.GetMute)
|
|
||||||
friendRouterGroup.POST("/pin", f.PinFriend)
|
friendRouterGroup.POST("/pin", f.PinFriend)
|
||||||
friendRouterGroup.POST("/unpin", f.UnpinFriend)
|
friendRouterGroup.POST("/unpin", f.UnpinFriend)
|
||||||
}
|
}
|
||||||
@ -358,6 +356,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
|
|||||||
conversationGroup.POST("/get_owner_conversation", c.GetOwnerConversation)
|
conversationGroup.POST("/get_owner_conversation", c.GetOwnerConversation)
|
||||||
conversationGroup.POST("/get_not_notify_conversation_ids", c.GetNotNotifyConversationIDs)
|
conversationGroup.POST("/get_not_notify_conversation_ids", c.GetNotNotifyConversationIDs)
|
||||||
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
|
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
|
||||||
|
conversationGroup.POST("/set_mute", c.SetMute)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -49,7 +49,6 @@ type conversationServer struct {
|
|||||||
pbconversation.UnimplementedConversationServer
|
pbconversation.UnimplementedConversationServer
|
||||||
conversationDatabase controller.ConversationDatabase
|
conversationDatabase controller.ConversationDatabase
|
||||||
msgBurnDeadlineDB database.MsgBurnDeadline
|
msgBurnDeadlineDB database.MsgBurnDeadline
|
||||||
userMuteDB controller.UserMuteDatabase
|
|
||||||
|
|
||||||
conversationNotificationSender *ConversationNotificationSender
|
conversationNotificationSender *ConversationNotificationSender
|
||||||
config *Config
|
config *Config
|
||||||
@ -86,10 +85,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userMuteMongoDB, err := mgo.NewUserMuteMongo(mgocli.GetDB())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
userConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -109,7 +104,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
conversationDatabase: controller.NewConversationDatabase(conversationDB,
|
conversationDatabase: controller.NewConversationDatabase(conversationDB,
|
||||||
redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
|
redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
|
||||||
msgBurnDeadlineDB: msgBurnDeadlineDB,
|
msgBurnDeadlineDB: msgBurnDeadlineDB,
|
||||||
userMuteDB: controller.NewUserMuteDatabase(userMuteMongoDB),
|
|
||||||
userClient: rpcli.NewUserClient(userConn),
|
userClient: rpcli.NewUserClient(userConn),
|
||||||
groupClient: rpcli.NewGroupClient(groupConn),
|
groupClient: rpcli.NewGroupClient(groupConn),
|
||||||
msgClient: msgClient,
|
msgClient: msgClient,
|
||||||
@ -202,14 +196,14 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
}
|
}
|
||||||
conversation_notPinTime[time] = conversationID
|
conversation_notPinTime[time] = conversationID
|
||||||
}
|
}
|
||||||
if c.userMuteDB != nil {
|
for _, v := range conversations {
|
||||||
for _, v := range conversations {
|
elem, ok := conversationMsg[v.ConversationID]
|
||||||
elem, ok := conversationMsg[v.ConversationID]
|
if !ok {
|
||||||
if !ok {
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
c.fillConversationElemUserMute(ctx, c.userMuteDB, req.UserID, elem, v.ConversationType, v.UserID)
|
|
||||||
}
|
}
|
||||||
|
elem.MuteDuration = v.MuteDuration
|
||||||
|
elem.MuteEndTime = v.MuteEndTime
|
||||||
|
elem.IsMuted = computeIsMuted(v.MuteDuration, v.MuteEndTime)
|
||||||
}
|
}
|
||||||
resp = &pbconversation.GetSortedConversationListResp{
|
resp = &pbconversation.GetSortedConversationListResp{
|
||||||
ConversationTotal: int64(len(chatLogs)),
|
ConversationTotal: int64(len(chatLogs)),
|
||||||
@ -916,3 +910,34 @@ func (c *conversationServer) ClearBurnExpiredMsgs(ctx context.Context, req *pbco
|
|||||||
}
|
}
|
||||||
return &pbconversation.ClearBurnExpiredMsgsResp{Count: processed}, nil
|
return &pbconversation.ClearBurnExpiredMsgsResp{Count: processed}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *conversationServer) SetConversationMute(ctx context.Context, req *pbconversation.SetConversationMuteReq) (*pbconversation.SetConversationMuteResp, error) {
|
||||||
|
var (
|
||||||
|
muteDuration int32
|
||||||
|
muteEndTime int64
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case req.Duration == 0:
|
||||||
|
// 取消静音:清零所有静音字段
|
||||||
|
case req.Duration == -1:
|
||||||
|
// 永久静音
|
||||||
|
muteDuration = -1
|
||||||
|
default:
|
||||||
|
// 定时静音
|
||||||
|
muteDuration = req.Duration
|
||||||
|
muteEndTime = time.Now().Unix() + int64(req.Duration)
|
||||||
|
}
|
||||||
|
if err := c.conversationDatabase.UpdateUsersConversationField(
|
||||||
|
ctx,
|
||||||
|
[]string{req.OwnerUserID},
|
||||||
|
req.ConversationID,
|
||||||
|
map[string]any{
|
||||||
|
"mute_duration": muteDuration,
|
||||||
|
"mute_end_time": muteEndTime,
|
||||||
|
},
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.conversationNotificationSender.ConversationChangeNotification(ctx, req.OwnerUserID, []string{req.ConversationID})
|
||||||
|
return &pbconversation.SetConversationMuteResp{}, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -4,95 +4,37 @@ package conversation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
|
||||||
"github.com/openimsdk/protocol/constant"
|
|
||||||
pbconversation "github.com/openimsdk/protocol/conversation"
|
pbconversation "github.com/openimsdk/protocol/conversation"
|
||||||
"github.com/openimsdk/tools/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// int64MuteDurationToProto 将 user_mute 的秒数配置写入 Conversation.muteDuration(int32);正数过大时截断。
|
// computeIsMuted 根据会话模型中存储的 mute_duration 和 mute_end_time 计算当前是否处于静音状态:
|
||||||
func int64MuteDurationToProto(d int64) int32 {
|
// - duration == 0 且 end == 0:未静音
|
||||||
if d > int64(math.MaxInt32) {
|
// - duration == -1 且 end == 0:永久静音
|
||||||
return math.MaxInt32
|
// - end > 0 且 end > now:定时静音仍有效
|
||||||
|
// - end > 0 且 end <= now:定时静音已过期,视为未静音
|
||||||
|
func computeIsMuted(muteDuration int32, muteEndTime int64) bool {
|
||||||
|
if muteDuration == 0 && muteEndTime == 0 {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if d < int64(math.MinInt32) {
|
if muteDuration == -1 && muteEndTime == 0 {
|
||||||
return math.MinInt32
|
return true
|
||||||
}
|
}
|
||||||
return int32(d)
|
return muteEndTime > time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
// conversationMuteFromRecord 与 relation.GetMute 判定一致:未记录/已过期则未静音;永久为 duration=-1 且 end=0。
|
// fillConversationUserMute 根据会话模型字段(已由 ConversationDB2Pb 通过 CopyStructFields 填入
|
||||||
func conversationMuteFromRecord(rec *model.UserMute, nowUnix int64) (isMuted bool, muteDuration int32, muteEndTime int64) {
|
// conv.MuteDuration / conv.MuteEndTime)计算并设置 conv.IsMuted,无需额外数据库查询。
|
||||||
if rec == nil {
|
func (c *conversationServer) fillConversationUserMute(_ context.Context, conv *pbconversation.Conversation) {
|
||||||
return false, 0, 0
|
if conv == nil {
|
||||||
}
|
|
||||||
if rec.MuteEndTime != 0 && rec.MuteEndTime <= nowUnix {
|
|
||||||
return false, 0, 0
|
|
||||||
}
|
|
||||||
d := rec.MuteDuration
|
|
||||||
if d == 0 && rec.MuteEndTime == 0 {
|
|
||||||
d = -1
|
|
||||||
}
|
|
||||||
md := int64MuteDurationToProto(d)
|
|
||||||
me := rec.MuteEndTime
|
|
||||||
isMuted = (md == -1) || (me > nowUnix)
|
|
||||||
return isMuted, md, me
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *conversationServer) fillConversationUserMute(ctx context.Context, conv *pbconversation.Conversation) {
|
|
||||||
if c == nil || c.userMuteDB == nil || conv == nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if conv.ConversationType != constant.SingleChatType || conv.UserID == "" {
|
conv.IsMuted = computeIsMuted(conv.MuteDuration, conv.MuteEndTime)
|
||||||
return
|
|
||||||
}
|
|
||||||
rec, err := c.userMuteDB.Get(ctx, conv.OwnerUserID, conv.UserID)
|
|
||||||
if err != nil {
|
|
||||||
log.ZWarn(ctx, "fillConversationUserMute Get", err, "owner", conv.OwnerUserID, "peer", conv.UserID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
now := time.Now().Unix()
|
|
||||||
isMuted, dur, end := conversationMuteFromRecord(rec, now)
|
|
||||||
conv.IsMuted = isMuted
|
|
||||||
conv.MuteDuration = dur
|
|
||||||
conv.MuteEndTime = end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) fillConversationsUserMute(ctx context.Context, list []*pbconversation.Conversation) {
|
func (c *conversationServer) fillConversationsUserMute(ctx context.Context, list []*pbconversation.Conversation) {
|
||||||
if len(list) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, conv := range list {
|
for _, conv := range list {
|
||||||
c.fillConversationUserMute(ctx, conv)
|
c.fillConversationUserMute(ctx, conv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) fillConversationElemUserMute(
|
|
||||||
ctx context.Context,
|
|
||||||
db controller.UserMuteDatabase,
|
|
||||||
ownerUserID string,
|
|
||||||
elem *pbconversation.ConversationElem,
|
|
||||||
conversationType int32,
|
|
||||||
peerUserID string,
|
|
||||||
) {
|
|
||||||
if db == nil || elem == nil || ownerUserID == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if conversationType != constant.SingleChatType || peerUserID == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rec, err := db.Get(ctx, ownerUserID, peerUserID)
|
|
||||||
if err != nil {
|
|
||||||
log.ZWarn(ctx, "fillConversationElemUserMute Get", err, "owner", ownerUserID, "peer", peerUserID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
now := time.Now().Unix()
|
|
||||||
isMuted, dur, end := conversationMuteFromRecord(rec, now)
|
|
||||||
elem.IsMuted = isMuted
|
|
||||||
elem.MuteDuration = dur
|
|
||||||
elem.MuteEndTime = end
|
|
||||||
}
|
|
||||||
|
|||||||
@ -72,7 +72,6 @@ type msgServer struct {
|
|||||||
conversationClient *rpcli.ConversationClient
|
conversationClient *rpcli.ConversationClient
|
||||||
spamReportDB database.SpamReport
|
spamReportDB database.SpamReport
|
||||||
globalBlackDB controller.UserGlobalBlackDatabase
|
globalBlackDB controller.UserGlobalBlackDatabase
|
||||||
userMuteDB controller.UserMuteDatabase
|
|
||||||
msgBurnDeadlineDB database.MsgBurnDeadline
|
msgBurnDeadlineDB database.MsgBurnDeadline
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +137,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userMuteMgo, err := mgo.NewUserMuteMongo(mgocli.GetDB())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := &msgServer{
|
s := &msgServer{
|
||||||
MsgDatabase: msgDatabase,
|
MsgDatabase: msgDatabase,
|
||||||
RegisterCenter: client,
|
RegisterCenter: client,
|
||||||
@ -154,7 +149,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
|
|||||||
conversationClient: conversationClient,
|
conversationClient: conversationClient,
|
||||||
spamReportDB: spamReportDB,
|
spamReportDB: spamReportDB,
|
||||||
globalBlackDB: controller.NewUserGlobalBlackDatabase(globalBlackMgo),
|
globalBlackDB: controller.NewUserGlobalBlackDatabase(globalBlackMgo),
|
||||||
userMuteDB: controller.NewUserMuteDatabase(userMuteMgo),
|
|
||||||
msgBurnDeadlineDB: msgBurnDeadlineDB,
|
msgBurnDeadlineDB: msgBurnDeadlineDB,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -325,14 +325,20 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(ctx context.Context, us
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第四优先级:用户静音设置(user_mute 集合,支持好友与非好友)
|
// 第四优先级:会话静音设置(存储于 conversations 集合的 mute_duration/mute_end_time)
|
||||||
// 无论会话记录是否存在均检查,以支持对非好友的静音
|
conv, convErr := m.ConversationLocalCache.GetConversation(ctx, userID, conversationID)
|
||||||
if m.userMuteDB != nil {
|
if convErr != nil && !errs.ErrRecordNotFound.Is(convErr) {
|
||||||
muted, err := m.userMuteDB.IsMuted(ctx, userID, pb.MsgData.SendID)
|
return false, convErr
|
||||||
if err != nil {
|
}
|
||||||
return false, err
|
if convErr == nil && conv != nil {
|
||||||
|
var isMuted bool
|
||||||
|
switch {
|
||||||
|
case conv.MuteDuration == -1 && conv.MuteEndTime == 0:
|
||||||
|
isMuted = true
|
||||||
|
case conv.MuteEndTime > 0:
|
||||||
|
isMuted = conv.MuteEndTime > time.Now().Unix()
|
||||||
}
|
}
|
||||||
if muted {
|
if isMuted {
|
||||||
if pb.MsgData.Options == nil {
|
if pb.MsgData.Options == nil {
|
||||||
pb.MsgData.Options = make(map[string]bool, 10)
|
pb.MsgData.Options = make(map[string]bool, 10)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,4 +37,6 @@ type Conversation struct {
|
|||||||
IsMsgDestruct bool `bson:"is_msg_destruct"`
|
IsMsgDestruct bool `bson:"is_msg_destruct"`
|
||||||
MsgDestructTime int64 `bson:"msg_destruct_time"`
|
MsgDestructTime int64 `bson:"msg_destruct_time"`
|
||||||
LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"`
|
LatestMsgDestructTime time.Time `bson:"latest_msg_destruct_time"`
|
||||||
|
MuteDuration int32 `bson:"mute_duration"`
|
||||||
|
MuteEndTime int64 `bson:"mute_end_time"`
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user