fix(messages): sync preserve private dialogs after clearing history
This commit is contained in:
parent
3926db7762
commit
e22fac1c3f
19 changed files with 923 additions and 231 deletions
|
|
@ -33,7 +33,7 @@ func (s *MessageStore) DeleteMessages(_ context.Context, req domain.DeleteMessag
|
|||
if req.Revoke && len(revokeUIDs) > 0 {
|
||||
deleted = append(deleted, s.deleteMemoryMessagesByUIDLocked(revokeUIDs, req.OwnerUserID)...)
|
||||
}
|
||||
return s.finishMemoryDeleteLocked(res, deleted, req.Date, false), nil
|
||||
return s.finishMemoryDeleteLocked(res, deleted, req.Date, nil), nil
|
||||
}
|
||||
|
||||
type deletedMemoryMessage struct {
|
||||
|
|
@ -45,8 +45,13 @@ type deletedMemoryMessage struct {
|
|||
randomID int64
|
||||
}
|
||||
|
||||
func (s *MessageStore) finishMemoryDeleteLocked(res domain.DeleteMessagesResult, deleted []deletedMemoryMessage, date int, preserveEmptyDialogs bool) domain.DeleteMessagesResult {
|
||||
if len(deleted) == 0 {
|
||||
type memoryHistoryClearAnchor struct {
|
||||
message domain.Message
|
||||
materialized bool
|
||||
}
|
||||
|
||||
func (s *MessageStore) finishMemoryDeleteLocked(res domain.DeleteMessagesResult, deleted []deletedMemoryMessage, date int, anchors map[int64]memoryHistoryClearAnchor) domain.DeleteMessagesResult {
|
||||
if len(deleted) == 0 && len(anchors) == 0 {
|
||||
return res
|
||||
}
|
||||
idsByOwner := make(map[int64][]int)
|
||||
|
|
@ -64,57 +69,153 @@ func (s *MessageStore) finishMemoryDeleteLocked(res domain.DeleteMessagesResult,
|
|||
}
|
||||
peersByOwner[row.userID][row.peer] = struct{}{}
|
||||
}
|
||||
if s.dialogs != nil {
|
||||
s.dialogs.mu.Lock()
|
||||
for userID, peers := range peersByOwner {
|
||||
for peer := range peers {
|
||||
s.rebuildMemoryDialogLocked(userID, peer, preserveEmptyDialogs)
|
||||
}
|
||||
for userID, anchor := range anchors {
|
||||
if peersByOwner[userID] == nil {
|
||||
peersByOwner[userID] = make(map[domain.Peer]struct{})
|
||||
}
|
||||
s.dialogs.mu.Unlock()
|
||||
peersByOwner[userID][anchor.message.Peer] = struct{}{}
|
||||
}
|
||||
ownerIDs := make([]int64, 0, len(idsByOwner))
|
||||
ownerSet := make(map[int64]struct{}, len(idsByOwner)+len(anchors))
|
||||
for userID := range idsByOwner {
|
||||
ownerSet[userID] = struct{}{}
|
||||
}
|
||||
for userID, anchor := range anchors {
|
||||
if !anchor.materialized {
|
||||
ownerSet[userID] = struct{}{}
|
||||
}
|
||||
}
|
||||
ownerIDs := make([]int64, 0, len(ownerSet))
|
||||
for userID := range ownerSet {
|
||||
ownerIDs = append(ownerIDs, userID)
|
||||
}
|
||||
sort.Slice(ownerIDs, func(i, j int) bool { return ownerIDs[i] < ownerIDs[j] })
|
||||
for _, userID := range ownerIDs {
|
||||
ids := normalizeMemoryMessageIDs(idsByOwner[userID])
|
||||
if len(ids) == 0 {
|
||||
anchor, hasAnchor := anchors[userID]
|
||||
materializeAnchor := hasAnchor && !anchor.materialized
|
||||
totalPtsCount := len(ids)
|
||||
if materializeAnchor {
|
||||
totalPtsCount += 2
|
||||
}
|
||||
if totalPtsCount == 0 {
|
||||
continue
|
||||
}
|
||||
pts := s.nextPtsNLocked(userID, len(ids))
|
||||
event := domain.UpdateEvent{
|
||||
pts := s.nextPtsNLocked(userID, totalPtsCount)
|
||||
cursor := pts - totalPtsCount
|
||||
item := domain.DeletedMessagesForUser{
|
||||
UserID: userID,
|
||||
Type: domain.UpdateEventDeleteMessages,
|
||||
MessageIDs: ids,
|
||||
Pts: pts,
|
||||
PtsCount: len(ids),
|
||||
Date: date,
|
||||
MessageIDs: ids,
|
||||
PtsCount: totalPtsCount,
|
||||
Events: make([]domain.UpdateEvent, 0, 3),
|
||||
}
|
||||
for _, row := range deleted {
|
||||
if row.userID != userID || row.messageSenderID != userID || row.randomID == 0 || row.privateMessageID == 0 {
|
||||
continue
|
||||
if len(ids) > 0 {
|
||||
cursor += len(ids)
|
||||
event := domain.UpdateEvent{
|
||||
UserID: userID,
|
||||
Type: domain.UpdateEventDeleteMessages,
|
||||
Pts: cursor,
|
||||
PtsCount: len(ids),
|
||||
Date: date,
|
||||
MessageIDs: ids,
|
||||
}
|
||||
key := privateSendDedupKey{senderUserID: userID, randomID: row.randomID}
|
||||
record, ok := s.privateSendDedup[key]
|
||||
if !ok {
|
||||
continue
|
||||
for _, row := range deleted {
|
||||
if row.userID != userID || row.messageSenderID != userID || row.randomID == 0 || row.privateMessageID == 0 {
|
||||
continue
|
||||
}
|
||||
key := privateSendDedupKey{senderUserID: userID, randomID: row.randomID}
|
||||
record, ok := s.privateSendDedup[key]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
cloned := cloneUpdateEvent(event)
|
||||
record.senderDeleteEvent = &cloned
|
||||
s.privateSendDedup[key] = record
|
||||
}
|
||||
cloned := cloneUpdateEvent(event)
|
||||
record.senderDeleteEvent = &cloned
|
||||
s.privateSendDedup[key] = record
|
||||
item.Event = event
|
||||
item.Events = append(item.Events, event)
|
||||
}
|
||||
res.Deleted = append(res.Deleted, domain.DeletedMessagesForUser{
|
||||
UserID: userID,
|
||||
MessageIDs: ids,
|
||||
Event: event,
|
||||
})
|
||||
if materializeAnchor {
|
||||
readPts := cursor + 1
|
||||
editPts := readPts + 1
|
||||
msg := domain.NewHistoryClearMessage(
|
||||
userID,
|
||||
anchor.message.Peer,
|
||||
anchor.message.ID,
|
||||
anchor.message.UID,
|
||||
anchor.message.Date,
|
||||
editPts,
|
||||
)
|
||||
for i := range s.m[userID] {
|
||||
if s.m[userID][i].ID == anchor.message.ID && s.m[userID][i].Peer == anchor.message.Peer {
|
||||
s.m[userID][i] = msg
|
||||
break
|
||||
}
|
||||
}
|
||||
if byMessage := s.savedMessageTags[userID]; byMessage != nil {
|
||||
delete(byMessage, anchor.message.ID)
|
||||
if len(byMessage) == 0 {
|
||||
delete(s.savedMessageTags, userID)
|
||||
}
|
||||
}
|
||||
readEvent := domain.UpdateEvent{
|
||||
UserID: userID,
|
||||
Type: domain.UpdateEventReadHistoryInbox,
|
||||
Pts: readPts,
|
||||
PtsCount: 1,
|
||||
Date: date,
|
||||
Peer: anchor.message.Peer,
|
||||
MaxID: anchor.message.ID,
|
||||
StillUnreadCount: 0,
|
||||
}
|
||||
editEvent := domain.UpdateEvent{
|
||||
UserID: userID,
|
||||
Type: domain.UpdateEventEditMessage,
|
||||
Pts: editPts,
|
||||
PtsCount: 1,
|
||||
Date: date,
|
||||
Message: cloneMessage(msg),
|
||||
}
|
||||
item.Events = append(item.Events, readEvent, editEvent)
|
||||
cursor = editPts
|
||||
}
|
||||
if s.dialogs != nil {
|
||||
s.dialogs.mu.Lock()
|
||||
for peer := range peersByOwner[userID] {
|
||||
s.rebuildMemoryDialogLocked(userID, peer)
|
||||
}
|
||||
if materializeAnchor {
|
||||
s.advanceMemoryHistoryClearDialogLocked(userID, anchor.message.Peer, anchor.message.ID)
|
||||
}
|
||||
s.dialogs.mu.Unlock()
|
||||
}
|
||||
if cursor != pts {
|
||||
panic(fmt.Sprintf("memory delete history pts cursor %d does not reach reserved pts %d", cursor, pts))
|
||||
}
|
||||
res.Deleted = append(res.Deleted, item)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *MessageStore) rebuildMemoryDialogLocked(userID int64, peer domain.Peer, preserveEmpty bool) {
|
||||
func (s *MessageStore) advanceMemoryHistoryClearDialogLocked(userID int64, peer domain.Peer, maxID int) {
|
||||
list := s.dialogs.m[userID]
|
||||
for i := range list.Dialogs {
|
||||
if list.Dialogs[i].Peer != peer {
|
||||
continue
|
||||
}
|
||||
if list.Dialogs[i].ReadInboxMaxID < maxID {
|
||||
list.Dialogs[i].ReadInboxMaxID = maxID
|
||||
}
|
||||
list.Dialogs[i].UnreadCount = 0
|
||||
list.Dialogs[i].UnreadMark = false
|
||||
list.Dialogs[i].UnreadMentions = 0
|
||||
list.Dialogs[i].UnreadReactions = 0
|
||||
break
|
||||
}
|
||||
s.dialogs.m[userID] = list
|
||||
}
|
||||
|
||||
func (s *MessageStore) rebuildMemoryDialogLocked(userID int64, peer domain.Peer) {
|
||||
list := s.dialogs.m[userID]
|
||||
topID := 0
|
||||
topDate := 0
|
||||
|
|
@ -135,22 +236,6 @@ func (s *MessageStore) rebuildMemoryDialogLocked(userID int64, peer domain.Peer,
|
|||
continue
|
||||
}
|
||||
if topID == 0 {
|
||||
if preserveEmpty {
|
||||
oldTop := dialog.TopMessage
|
||||
dialog.TopMessage = 0
|
||||
dialog.TopMessageDate = 0
|
||||
if dialog.ReadInboxMaxID < oldTop {
|
||||
dialog.ReadInboxMaxID = oldTop
|
||||
}
|
||||
if dialog.ReadOutboxMaxID < oldTop {
|
||||
dialog.ReadOutboxMaxID = oldTop
|
||||
}
|
||||
dialog.UnreadCount = 0
|
||||
dialog.UnreadMark = false
|
||||
dialog.UnreadMentions = 0
|
||||
dialog.UnreadReactions = 0
|
||||
dialogs = append(dialogs, dialog)
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, msg := range s.m[userID] {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue