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:
parent
85ba478c49
commit
10f6d9e89b
|
@ -8,7 +8,50 @@ import signal_type
|
||||||
type CommunitySignal* = ref object of Signal
|
type CommunitySignal* = ref object of Signal
|
||||||
community*: CommunityDto
|
community*: CommunityDto
|
||||||
|
|
||||||
|
type HistoryArchivesSignal* = ref object of Signal
|
||||||
|
communityId*: string
|
||||||
|
begin*: int
|
||||||
|
to*: int
|
||||||
|
|
||||||
proc fromEvent*(T: type CommunitySignal, event: JsonNode): CommunitySignal =
|
proc fromEvent*(T: type CommunitySignal, event: JsonNode): CommunitySignal =
|
||||||
result = CommunitySignal()
|
result = CommunitySignal()
|
||||||
result.signalType = SignalType.CommunityFound
|
result.signalType = SignalType.CommunityFound
|
||||||
result.community = event["event"].toCommunityDto()
|
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
|
||||||
|
|
|
@ -29,6 +29,14 @@ type SignalType* {.pure.} = enum
|
||||||
KeycardConnected = "keycard.connected"
|
KeycardConnected = "keycard.connected"
|
||||||
MailserverAvailable = "mailserver.available"
|
MailserverAvailable = "mailserver.available"
|
||||||
MailserverChanged = "mailserver.changed"
|
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
|
Unknown
|
||||||
|
|
||||||
proc event*(self:SignalType):string =
|
proc event*(self:SignalType):string =
|
||||||
|
|
|
@ -84,6 +84,14 @@ QtObject:
|
||||||
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
|
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
|
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.MailserverChanged: MailserverChangedSignal.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()
|
else: Signal()
|
||||||
|
|
||||||
result.signalType = signalType
|
result.signalType = signalType
|
||||||
|
|
|
@ -53,6 +53,13 @@ proc newController*(delegate: io_interface.AccessInterface, sectionId: string, i
|
||||||
proc delete*(self: Controller) =
|
proc delete*(self: Controller) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
proc getActiveChatId*(self: Controller): string =
|
||||||
|
if(self.activeSubItemId.len > 0):
|
||||||
|
return self.activeSubItemId
|
||||||
|
else:
|
||||||
|
return self.activeItemId
|
||||||
|
|
||||||
|
|
||||||
proc init*(self: Controller) =
|
proc init*(self: Controller) =
|
||||||
self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args):
|
self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args):
|
||||||
let args = MessagesArgs(e)
|
let args = MessagesArgs(e)
|
||||||
|
@ -154,6 +161,11 @@ proc init*(self: Controller) =
|
||||||
if (args.communityId == self.sectionId):
|
if (args.communityId == self.sectionId):
|
||||||
self.delegate.onReorderChatOrCategory(args.chatId, args.position)
|
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):
|
self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args):
|
||||||
var args = ContactArgs(e)
|
var args = ContactArgs(e)
|
||||||
self.delegate.onContactDetailsUpdated(args.contactId)
|
self.delegate.onContactDetailsUpdated(args.contactId)
|
||||||
|
@ -190,12 +202,6 @@ proc init*(self: Controller) =
|
||||||
proc getMySectionId*(self: Controller): string =
|
proc getMySectionId*(self: Controller): string =
|
||||||
return self.sectionId
|
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 =
|
proc isCommunity*(self: Controller): bool =
|
||||||
return self.isCommunitySection
|
return self.isCommunitySection
|
||||||
|
|
||||||
|
|
|
@ -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/tasks/[qt, threadpool]
|
||||||
import ../../../app/core/signals/types
|
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* = 20
|
||||||
const MESSAGES_PER_PAGE_MAX* = 300
|
const MESSAGES_PER_PAGE_MAX* = 300
|
||||||
const CURSOR_VALUE_IGNORE = "ignore"
|
const CURSOR_VALUE_IGNORE = "ignore"
|
||||||
|
const WEEK_AS_MILLISECONDS = initDuration(seconds = 60*60*24*7).inMilliSeconds
|
||||||
|
|
||||||
# Signals which may be emitted by this service:
|
# Signals which may be emitted by this service:
|
||||||
const SIGNAL_MESSAGES_LOADED* = "messagesLoaded"
|
const SIGNAL_MESSAGES_LOADED* = "messagesLoaded"
|
||||||
|
@ -49,6 +50,7 @@ const SIGNAL_MESSAGE_DELETION* = "messageDeleted"
|
||||||
const SIGNAL_MESSAGE_EDITED* = "messageEdited"
|
const SIGNAL_MESSAGE_EDITED* = "messageEdited"
|
||||||
const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded"
|
const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded"
|
||||||
const SIGNAL_MENTIONED_IN_EDITED_MESSAGE* = "mentionedInEditedMessage"
|
const SIGNAL_MENTIONED_IN_EDITED_MESSAGE* = "mentionedInEditedMessage"
|
||||||
|
const SIGNAL_RELOAD_MESSAGES* = "reloadMessages"
|
||||||
|
|
||||||
include async_tasks
|
include async_tasks
|
||||||
|
|
||||||
|
@ -94,6 +96,9 @@ type
|
||||||
LinkPreviewDataArgs* = ref object of Args
|
LinkPreviewDataArgs* = ref object of Args
|
||||||
response*: string
|
response*: string
|
||||||
|
|
||||||
|
ReloadMessagesArgs* = ref object of Args
|
||||||
|
communityId*: string
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type Service* = ref object of QObject
|
type Service* = ref object of QObject
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
|
@ -222,6 +227,37 @@ QtObject:
|
||||||
reactionId: r.id, reactionFrom: r.`from`)
|
reactionId: r.id, reactionFrom: r.`from`)
|
||||||
self.events.emit(SIGNAL_MESSAGE_REACTION_FROM_OTHERS, data)
|
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) =
|
proc init*(self: Service) =
|
||||||
self.events.on(SignalType.Message.event) do(e: Args):
|
self.events.on(SignalType.Message.event) do(e: Args):
|
||||||
var receivedData = MessageSignal(e)
|
var receivedData = MessageSignal(e)
|
||||||
|
@ -239,13 +275,18 @@ QtObject:
|
||||||
if (receivedData.emojiReactions.len > 0):
|
if (receivedData.emojiReactions.len > 0):
|
||||||
self.handleEmojiReactionsUpdate(receivedData.emojiReactions)
|
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 =
|
proc initialMessagesFetched(self: Service, chatId: string): bool =
|
||||||
return self.msgCursor.hasKey(chatId)
|
return self.msgCursor.hasKey(chatId)
|
||||||
|
|
||||||
proc getCurrentMessageCursor(self: Service, chatId: string): string =
|
proc getCurrentMessageCursor(self: Service, chatId: string): string =
|
||||||
if(not self.msgCursor.hasKey(chatId)):
|
if(not self.msgCursor.hasKey(chatId)):
|
||||||
self.msgCursor[chatId] = ""
|
self.msgCursor[chatId] = ""
|
||||||
|
|
||||||
return self.msgCursor[chatId]
|
return self.msgCursor[chatId]
|
||||||
|
|
||||||
proc getCurrentPinnedMessageCursor(self: Service, chatId: string): string =
|
proc getCurrentPinnedMessageCursor(self: Service, chatId: string): string =
|
||||||
|
@ -276,6 +317,15 @@ QtObject:
|
||||||
var chatId: string
|
var chatId: string
|
||||||
discard responseObj.getProp("chatId", chatId)
|
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.
|
# this is important case we don't want to fetch the same messages multiple times.
|
||||||
self.lastUsedMsgCursor[chatId] = self.msgCursor[chatId]
|
self.lastUsedMsgCursor[chatId] = self.msgCursor[chatId]
|
||||||
self.lastUsedPinnedMsgCursor[chatId] = self.pinnedMsgCursor[chatId]
|
self.lastUsedPinnedMsgCursor[chatId] = self.pinnedMsgCursor[chatId]
|
||||||
|
|
|
@ -32,6 +32,14 @@ proc decode*(jsonSignal: JsonNode): Signal =
|
||||||
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
|
of SignalType.KeycardConnected: KeycardConnectedSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
|
of SignalType.MailserverAvailable: MailserverAvailableSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.MailserverChanged: MailserverChangedSignal.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()
|
else: Signal()
|
||||||
|
|
||||||
result.signalType = signalType
|
result.signalType = signalType
|
||||||
|
|
Loading…
Reference in New Issue