feat: reload community chats when history messages have been downloaded

This introduces the new signal types related to the community archive
protocol and makes Status Desktop listen to the download event which is
emitted by status-go every time history archives were downloaded.

If the downloaded archive covers data within the recent 7 days, it
causes Status Desktop to reload the corresponding chats.
This commit is contained in:
Pascal Precht 2022-04-08 10:11:43 +02:00 committed by r4bbit.eth
parent 85ba478c49
commit 10f6d9e89b
6 changed files with 131 additions and 8 deletions

View File

@ -8,7 +8,50 @@ import signal_type
type CommunitySignal* = ref object of Signal
community*: CommunityDto
type HistoryArchivesSignal* = ref object of Signal
communityId*: string
begin*: int
to*: int
proc fromEvent*(T: type CommunitySignal, event: JsonNode): CommunitySignal =
result = CommunitySignal()
result.signalType = SignalType.CommunityFound
result.community = event["event"].toCommunityDto()
proc createFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal()
result.communityId = event["event"]{"communityId"}.getStr()
result.begin = event["event"]{"from"}.getInt()
result.to = event["event"]{"to"}.getInt()
proc historyArchivesProtocolEnabledFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchivesProtocolEnabled
proc historyArchivesProtocolDisabledFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchivesProtocolDisabled
proc creatingHistoryArchivesFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.CreatingHistoryArchives
proc historyArchivesCreatedFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchivesCreated
proc noHistoryArchivesCreatedFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.NoHistoryArchivesCreated
proc historyArchivesSeedingFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchivesSeeding
proc historyArchivesUnseededFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchivesUnseeded
proc historyArchiveDownloadedFromEvent*(T: type HistoryArchivesSignal, event: JsonNode): HistoryArchivesSignal =
result = HistoryArchivesSignal.createFromEvent(event)
result.signalType = SignalType.HistoryArchiveDownloaded

View File

@ -29,6 +29,14 @@ type SignalType* {.pure.} = enum
KeycardConnected = "keycard.connected"
MailserverAvailable = "mailserver.available"
MailserverChanged = "mailserver.changed"
HistoryArchivesProtocolEnabled = "community.historyArchivesProtocolEnabled"
HistoryArchivesProtocolDisabled = "community.historyArchivesProtocolDisabled"
CreatingHistoryArchives = "community.creatingHistoryArchives"
HistoryArchivesCreated = "community.historyArchivesCreated"
NoHistoryArchivesCreated = "community.noHistoryArchivesCreated"
HistoryArchivesSeeding = "community.historyArchivesSeeding"
HistoryArchivesUnseeded = "community.historyArchivesUnseeded"
HistoryArchiveDownloaded = "community.historyArchiveDownloaded"
Unknown
proc event*(self:SignalType):string =

View File

@ -84,6 +84,14 @@ QtObject:
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
of SignalType.MailserverChanged: MailserverChangedSignal.fromEvent(jsonSignal)
of SignalType.HistoryArchivesProtocolEnabled: HistoryArchivesSignal.historyArchivesProtocolEnabledFromEvent(jsonSignal)
of SignalType.HistoryArchivesProtocolDisabled: HistoryArchivesSignal.historyArchivesProtocolDisabledFromEvent(jsonSignal)
of SignalType.CreatingHistoryArchives: HistoryArchivesSignal.creatingHistoryArchivesFromEvent(jsonSignal)
of SignalType.NoHistoryArchivesCreated: HistoryArchivesSignal.noHistoryArchivesCreatedFromEvent(jsonSignal)
of SignalType.HistoryArchivesCreated: HistoryArchivesSignal.historyArchivesCreatedFromEvent(jsonSignal)
of SignalType.HistoryArchivesSeeding: HistoryArchivesSignal.historyArchivesSeedingFromEvent(jsonSignal)
of SignalType.HistoryArchivesUnseeded: HistoryArchivesSignal.historyArchivesUnseededFromEvent(jsonSignal)
of SignalType.HistoryArchiveDownloaded: HistoryArchivesSignal.historyArchiveDownloadedFromEvent(jsonSignal)
else: Signal()
result.signalType = signalType

View File

@ -53,6 +53,13 @@ proc newController*(delegate: io_interface.AccessInterface, sectionId: string, i
proc delete*(self: Controller) =
discard
proc getActiveChatId*(self: Controller): string =
if(self.activeSubItemId.len > 0):
return self.activeSubItemId
else:
return self.activeItemId
proc init*(self: Controller) =
self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args):
let args = MessagesArgs(e)
@ -154,6 +161,11 @@ proc init*(self: Controller) =
if (args.communityId == self.sectionId):
self.delegate.onReorderChatOrCategory(args.chatId, args.position)
self.events.on(SIGNAL_RELOAD_MESSAGES) do(e: Args):
let args = ReloadMessagesArgs(e)
if (args.communityId == self.sectionId):
self.messageService.asyncLoadInitialMessagesForChat(self.getActiveChatId())
self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args):
var args = ContactArgs(e)
self.delegate.onContactDetailsUpdated(args.contactId)
@ -190,12 +202,6 @@ proc init*(self: Controller) =
proc getMySectionId*(self: Controller): string =
return self.sectionId
proc getActiveChatId*(self: Controller): string =
if(self.activeSubItemId.len > 0):
return self.activeSubItemId
else:
return self.activeItemId
proc isCommunity*(self: Controller): bool =
return self.isCommunitySection

View File

@ -1,4 +1,4 @@
import NimQml, tables, json, re, sequtils, strformat, strutils, chronicles
import NimQml, tables, json, re, sequtils, strformat, strutils, chronicles, times
import ../../../app/core/tasks/[qt, threadpool]
import ../../../app/core/signals/types
@ -34,6 +34,7 @@ let NEW_LINE = re"\n|\r" #must be defined as let, not const
const MESSAGES_PER_PAGE* = 20
const MESSAGES_PER_PAGE_MAX* = 300
const CURSOR_VALUE_IGNORE = "ignore"
const WEEK_AS_MILLISECONDS = initDuration(seconds = 60*60*24*7).inMilliSeconds
# Signals which may be emitted by this service:
const SIGNAL_MESSAGES_LOADED* = "messagesLoaded"
@ -49,6 +50,7 @@ const SIGNAL_MESSAGE_DELETION* = "messageDeleted"
const SIGNAL_MESSAGE_EDITED* = "messageEdited"
const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded"
const SIGNAL_MENTIONED_IN_EDITED_MESSAGE* = "mentionedInEditedMessage"
const SIGNAL_RELOAD_MESSAGES* = "reloadMessages"
include async_tasks
@ -94,6 +96,9 @@ type
LinkPreviewDataArgs* = ref object of Args
response*: string
ReloadMessagesArgs* = ref object of Args
communityId*: string
QtObject:
type Service* = ref object of QObject
events: EventEmitter
@ -222,6 +227,37 @@ QtObject:
reactionId: r.id, reactionFrom: r.`from`)
self.events.emit(SIGNAL_MESSAGE_REACTION_FROM_OTHERS, data)
proc handleMessagesReload(self: Service, communityId: string) =
var keys = newSeq[string]()
for k in self.msgCursor.keys:
if k.startsWith(communityId):
keys.add(k)
for k in keys:
self.msgCursor.del(k)
keys = @[]
for k in self.lastUsedMsgCursor.keys:
if k.startsWith(communityId):
keys.add(k)
for k in keys:
self.lastUsedMsgCursor.del(k)
keys = @[]
for k in self.pinnedMsgCursor.keys:
if k.startsWith(communityId):
keys.add(k)
for k in keys:
self.pinnedMsgCursor.del(k)
keys = @[]
for k in self.lastUsedPinnedMsgCursor.keys:
if k.startsWith(communityId):
keys.add(k)
for k in keys:
self.lastUsedPinnedMsgCursor.del(k)
self.events.emit(SIGNAL_RELOAD_MESSAGES, ReloadMessagesArgs(communityId: communityId))
proc init*(self: Service) =
self.events.on(SignalType.Message.event) do(e: Args):
var receivedData = MessageSignal(e)
@ -239,13 +275,18 @@ QtObject:
if (receivedData.emojiReactions.len > 0):
self.handleEmojiReactionsUpdate(receivedData.emojiReactions)
self.events.on(SignalType.HistoryArchiveDownloaded.event) do(e: Args):
var receivedData = HistoryArchivesSignal(e)
if now().toTime().toUnix()-receivedData.begin <= WEEK_AS_MILLISECONDS:
# we don't need to reload the messages for archives older than 7 days
self.handleMessagesReload(receivedData.communityId)
proc initialMessagesFetched(self: Service, chatId: string): bool =
return self.msgCursor.hasKey(chatId)
proc getCurrentMessageCursor(self: Service, chatId: string): string =
if(not self.msgCursor.hasKey(chatId)):
self.msgCursor[chatId] = ""
return self.msgCursor[chatId]
proc getCurrentPinnedMessageCursor(self: Service, chatId: string): string =
@ -276,6 +317,15 @@ QtObject:
var chatId: string
discard responseObj.getProp("chatId", chatId)
if not self.msgCursor.hasKey(chatId):
self.msgCursor[chatId] = ""
if not self.lastUsedMsgCursor.hasKey(chatId):
self.lastUsedMsgCursor[chatId] = ""
if not self.pinnedMsgCursor.hasKey(chatId):
self.pinnedMsgCursor[chatId] = ""
if not self.lastUsedPinnedMsgCursor.hasKey(chatId):
self.lastUsedPinnedMsgCursor[chatId] = ""
# this is important case we don't want to fetch the same messages multiple times.
self.lastUsedMsgCursor[chatId] = self.msgCursor[chatId]
self.lastUsedPinnedMsgCursor[chatId] = self.pinnedMsgCursor[chatId]

View File

@ -32,6 +32,14 @@ proc decode*(jsonSignal: JsonNode): Signal =
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
of SignalType.MailserverChanged: MailserverChangedSignal.fromEvent(jsonSignal)
of SignalType.HistoryArchivesProtocolEnabled: historyArchivesProtocolEnabledFromEvent(jsonSignal)
of SignalType.HistoryArchivesProtocolDisabled: historyArchivesProtocolDisabledFromEvent(jsonSignal)
of SignalType.CreatingHistoryArchives: creatingHistoryArchivesFromEvent(jsonSignal)
of SignalType.NoHistoryArchivesCreated: noHistoryArchivesCreatedFromEvent(jsonSignal)
of SignalType.HistoryArchivesCreated: historyArchivesCreatedFromEvent(jsonSignal)
of SignalType.HistoryArchivesSeeding: historyArchivesSeedingFromEvent(jsonSignal)
of SignalType.HistoryArchivesUnseeded: historyArchivesUnseededFromEvent(jsonSignal)
of SignalType.HistoryArchiveDownloaded: historyArchiveDownloadedFromEvent(jsonSignal)
else: Signal()
result.signalType = signalType