perf(ChatLoadingTime): Separate get chat messages and get pinned messages in different tasks

This commit is contained in:
Alex Jbanca 2023-04-12 12:50:42 +03:00 committed by Alex Jbanca
parent d5e5ba2796
commit d1ffa2e3b3
6 changed files with 105 additions and 49 deletions

View File

@ -58,8 +58,8 @@ proc delete*(self: Controller) =
self.events.disconnect() self.events.disconnect()
proc init*(self: Controller) = proc init*(self: Controller) =
self.events.on(SIGNAL_MESSAGES_LOADED) do(e:Args): self.events.on(SIGNAL_PINNED_MESSAGES_LOADED) do(e:Args):
let args = MessagesLoadedArgs(e) let args = PinnedMessagesLoadedArgs(e)
if(self.chatId != args.chatId or args.pinnedMessages.len == 0): if(self.chatId != args.chatId or args.pinnedMessages.len == 0):
return return
self.delegate.newPinnedMessagesLoaded(args.pinnedMessages) self.delegate.newPinnedMessagesLoaded(args.pinnedMessages)

View File

@ -58,7 +58,13 @@ proc init*(self: Controller) =
let args = MessagesLoadedArgs(e) let args = MessagesLoadedArgs(e)
if(self.chatId != args.chatId): if(self.chatId != args.chatId):
return return
self.delegate.newMessagesLoaded(args.messages, args.reactions, args.pinnedMessages) self.delegate.newMessagesLoaded(args.messages, args.reactions)
self.events.on(SIGNAL_PINNED_MESSAGES_LOADED) do(e:Args):
let args = PinnedMessagesLoadedArgs(e)
if(self.chatId != args.chatId):
return
self.delegate.newPinnedMessagesLoaded(args.pinnedMessages)
self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args): self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args):
var args = MessagesArgs(e) var args = MessagesArgs(e)

View File

@ -25,8 +25,10 @@ method updateChatIdentifier*(self: AccessInterface) {.base.} =
method updateChatFetchMoreMessages*(self: AccessInterface) {.base.} = method updateChatFetchMoreMessages*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method newMessagesLoaded*(self: AccessInterface, messages: seq[MessageDto], reactions: seq[ReactionDto], method newMessagesLoaded*(self: AccessInterface, messages: seq[MessageDto], reactions: seq[ReactionDto]) {.base.} =
pinnedMessages: seq[PinnedMessageDto]) {.base.} = raise newException(ValueError, "No implementation available")
method newPinnedMessagesLoaded*(self: AccessInterface, pinnedMessages: seq[PinnedMessageDto]) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onReactionAdded*(self: AccessInterface, messageId: string, emojiId: int, reactionId: string) {.base.} = method onReactionAdded*(self: AccessInterface, messageId: string, emojiId: int, reactionId: string) {.base.} =

View File

@ -221,8 +221,7 @@ method reevaluateViewLoadingState*(self: Module) =
not self.firstUnseenMessageState.initialized or not self.firstUnseenMessageState.initialized or
self.firstUnseenMessageState.fetching) self.firstUnseenMessageState.fetching)
method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto], method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto]) =
pinnedMessages: seq[PinnedMessageDto]) =
var viewItems: seq[Item] var viewItems: seq[Item]
if(messages.len > 0): if(messages.len > 0):
@ -327,11 +326,6 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
else: else:
error "wrong emoji id found when loading messages", methodName="newMessagesLoaded" error "wrong emoji id found when loading messages", methodName="newMessagesLoaded"
for p in pinnedMessages:
if(p.message.id == message.id):
item.pinned = true
item.pinnedBy = p.pinnedBy
if message.editedAt != 0: if message.editedAt != 0:
item.isEdited = true item.isEdited = true
@ -357,6 +351,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
self.initialMessagesLoaded = true self.initialMessagesLoaded = true
self.reevaluateViewLoadingState() self.reevaluateViewLoadingState()
method newPinnedMessagesLoaded*(self: Module, pinnedMessages: seq[PinnedMessageDto]) =
for p in pinnedMessages:
self.onPinMessage(p.message.id, p.pinnedBy)
method messagesAdded*(self: Module, messages: seq[MessageDto]) = method messagesAdded*(self: Module, messages: seq[MessageDto]) =
var items: seq[Item] var items: seq[Item]

View File

@ -12,7 +12,6 @@ type
AsyncFetchChatMessagesTaskArg = ref object of QObjectTaskArg AsyncFetchChatMessagesTaskArg = ref object of QObjectTaskArg
chatId: string chatId: string
msgCursor: string msgCursor: string
pinnedMsgCursor: string
limit: int limit: int
const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
@ -32,16 +31,6 @@ const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimc
responseJson["messages"] = messagesArr responseJson["messages"] = messagesArr
responseJson["messagesCursor"] = messagesCursor responseJson["messagesCursor"] = messagesCursor
# handle pinned messages
if(arg.pinnedMsgCursor != CURSOR_VALUE_IGNORE):
var pinnedMsgArr: JsonNode
var pinnedMsgCursor: JsonNode
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.pinnedMsgCursor, arg.limit)
discard pinnedMsgsResponse.result.getProp("cursor", pinnedMsgCursor)
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
responseJson["pinnedMessages"] = pinnedMsgArr
responseJson["pinnedMessagesCursor"] = pinnedMsgCursor
# handle reactions # handle reactions
if(arg.msgCursor != CURSOR_VALUE_IGNORE): if(arg.msgCursor != CURSOR_VALUE_IGNORE):
# messages and reactions are using the same cursor # messages and reactions are using the same cursor
@ -52,6 +41,28 @@ const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimc
arg.finish(responseJson) arg.finish(responseJson)
#################################################
# Async load pinned messages
#################################################
const asyncFetchPinnedChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncFetchChatMessagesTaskArg](argEncoded)
var responseJson = %*{
"chatId": arg.chatId
}
#handle pinned messages
if(arg.msgCursor != CURSOR_VALUE_IGNORE):
var pinnedMsgArr: JsonNode
var msgCursor: JsonNode
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.msgCursor, arg.limit)
discard pinnedMsgsResponse.result.getProp("cursor", msgCursor)
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
responseJson["pinnedMessages"] = pinnedMsgArr
responseJson["pinnedMessagesCursor"] = msgCursor
arg.finish(responseJson)
################################################# #################################################
# Async search messages # Async search messages
################################################# #################################################

View File

@ -40,6 +40,7 @@ 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"
const SIGNAL_PINNED_MESSAGES_LOADED* = "pinnedMessagesLoaded"
const SIGNAL_FIRST_UNSEEN_MESSAGE_LOADED* = "firstUnseenMessageLoaded" const SIGNAL_FIRST_UNSEEN_MESSAGE_LOADED* = "firstUnseenMessageLoaded"
const SIGNAL_NEW_MESSAGE_RECEIVED* = "newMessageReceived" const SIGNAL_NEW_MESSAGE_RECEIVED* = "newMessageReceived"
const SIGNAL_MESSAGE_PINNED* = "messagePinned" const SIGNAL_MESSAGE_PINNED* = "messagePinned"
@ -72,9 +73,12 @@ type
MessagesLoadedArgs* = ref object of Args MessagesLoadedArgs* = ref object of Args
chatId*: string chatId*: string
messages*: seq[MessageDto] messages*: seq[MessageDto]
pinnedMessages*: seq[PinnedMessageDto]
reactions*: seq[ReactionDto] reactions*: seq[ReactionDto]
PinnedMessagesLoadedArgs* = ref object of Args
chatId*: string
pinnedMessages*: seq[PinnedMessageDto]
MessagePinUnpinArgs* = ref object of Args MessagePinUnpinArgs* = ref object of Args
chatId*: string chatId*: string
messageId*: string messageId*: string
@ -188,16 +192,11 @@ QtObject:
let msgCursor = self.initOrGetMessageCursor(chatId) let msgCursor = self.initOrGetMessageCursor(chatId)
let msgCursorValue = if (msgCursor.isFetchable()): msgCursor.getValue() else: CURSOR_VALUE_IGNORE let msgCursorValue = if (msgCursor.isFetchable()): msgCursor.getValue() else: CURSOR_VALUE_IGNORE
let pinnedMsgCursor = self.initOrGetPinnedMessageCursor(chatId) if(msgCursorValue == CURSOR_VALUE_IGNORE):
let pinnedMsgCursorValue = if (pinnedMsgCursor.isFetchable()): pinnedMsgCursor.getValue() else: CURSOR_VALUE_IGNORE
if(msgCursorValue == CURSOR_VALUE_IGNORE and pinnedMsgCursorValue == CURSOR_VALUE_IGNORE):
return return
if(msgCursorValue != CURSOR_VALUE_IGNORE): if(msgCursorValue != CURSOR_VALUE_IGNORE):
msgCursor.setPending() msgCursor.setPending()
if (pinnedMsgCursorValue != CURSOR_VALUE_IGNORE):
pinnedMsgCursor.setPending()
let arg = AsyncFetchChatMessagesTaskArg( let arg = AsyncFetchChatMessagesTaskArg(
tptr: cast[ByteAddress](asyncFetchChatMessagesTask), tptr: cast[ByteAddress](asyncFetchChatMessagesTask),
@ -205,17 +204,39 @@ QtObject:
slot: "onAsyncLoadMoreMessagesForChat", slot: "onAsyncLoadMoreMessagesForChat",
chatId: chatId, chatId: chatId,
msgCursor: msgCursorValue, msgCursor: msgCursorValue,
pinnedMsgCursor: pinnedMsgCursorValue,
limit: if(limit <= MESSAGES_PER_PAGE_MAX): limit else: MESSAGES_PER_PAGE_MAX limit: if(limit <= MESSAGES_PER_PAGE_MAX): limit else: MESSAGES_PER_PAGE_MAX
) )
self.threadpool.start(arg) self.threadpool.start(arg)
proc asyncLoadPinnedMessagesForChat*(self: Service, chatId: string) =
if (chatId.len == 0):
error "empty chat id", procName="asyncLoadPinnedMessagesForChat"
return
let pinnedMsgCursor = self.initOrGetPinnedMessageCursor(chatId)
let pinnedMsgCursorValue = if (pinnedMsgCursor.isFetchable()): pinnedMsgCursor.getValue() else: CURSOR_VALUE_IGNORE
if(pinnedMsgCursorValue == CURSOR_VALUE_IGNORE):
return
pinnedMsgCursor.setPending()
let arg = AsyncFetchChatMessagesTaskArg(
tptr: cast[ByteAddress](asyncFetchPinnedChatMessagesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncLoadPinnedMessagesForChat",
chatId: chatId,
msgCursor: pinnedMsgCursorValue,
limit: MESSAGES_PER_PAGE_MAX
)
self.threadpool.start(arg)
proc asyncLoadInitialMessagesForChat*(self: Service, chatId: string) = proc asyncLoadInitialMessagesForChat*(self: Service, chatId: string) =
if(self.isChatCursorInitialized(chatId)): if(self.isChatCursorInitialized(chatId)):
let data = MessagesLoadedArgs(chatId: chatId, let data = MessagesLoadedArgs(chatId: chatId,
messages: @[], messages: @[],
pinnedMessages: @[],
reactions: @[]) reactions: @[])
self.events.emit(SIGNAL_MESSAGES_LOADED, data) self.events.emit(SIGNAL_MESSAGES_LOADED, data)
@ -389,30 +410,17 @@ QtObject:
weiStr.trimZeros() weiStr.trimZeros()
return (tokenStr, weiStr) return (tokenStr, weiStr)
proc onAsyncLoadMoreMessagesForChat*(self: Service, response: string) {.slot.} = proc onAsyncLoadPinnedMessagesForChat*(self: Service, response: string) {.slot.} =
let responseObj = response.parseJson let responseObj = response.parseJson
if (responseObj.kind != JObject): if (responseObj.kind != JObject):
info "load more messages response is not a json object" info "load pinned messages response is not a json object"
# notify view, this is important self.events.emit(SIGNAL_PINNED_MESSAGES_LOADED, PinnedMessagesLoadedArgs())
self.events.emit(SIGNAL_MESSAGES_LOADED, MessagesLoadedArgs())
return return
var chatId: string var chatId: string
discard responseObj.getProp("chatId", chatId) discard responseObj.getProp("chatId", chatId)
let msgCursor = self.initOrGetMessageCursor(chatId)
let pinnedMsgCursor = self.initOrGetPinnedMessageCursor(chatId) let pinnedMsgCursor = self.initOrGetPinnedMessageCursor(chatId)
# handling messages
var msgCursorValue: string
if(responseObj.getProp("messagesCursor", msgCursorValue)):
msgCursor.setValue(msgCursorValue)
var messagesArr: JsonNode
var messages: seq[MessageDto]
if(responseObj.getProp("messages", messagesArr)):
messages = map(messagesArr.getElems(), proc(x: JsonNode): MessageDto = x.toMessageDto())
# handling pinned messages # handling pinned messages
var pinnedMsgCursorValue: string var pinnedMsgCursorValue: string
if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursorValue)): if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursorValue)):
@ -426,6 +434,38 @@ QtObject:
# set initial number of pinned messages # set initial number of pinned messages
self.numOfPinnedMessagesPerChat[chatId] = pinnedMessages.len self.numOfPinnedMessagesPerChat[chatId] = pinnedMessages.len
let data = PinnedMessagesLoadedArgs(chatId: chatId,
pinnedMessages: pinnedMessages)
self.events.emit(SIGNAL_PINNED_MESSAGES_LOADED, data)
proc onAsyncLoadMoreMessagesForChat*(self: Service, response: string) {.slot.} =
let responseObj = response.parseJson
if (responseObj.kind != JObject):
info "load more messages response is not a json object"
# notify view, this is important
self.events.emit(SIGNAL_MESSAGES_LOADED, MessagesLoadedArgs())
return
var chatId: string
discard responseObj.getProp("chatId", chatId)
let msgCursor = self.initOrGetMessageCursor(chatId)
if(msgCursor.getValue() == ""):
# this is the first time we load messages for this chat
# we need to load pinned messages as well
self.asyncLoadPinnedMessagesForChat(chatId)
# handling messages
var msgCursorValue: string
if(responseObj.getProp("messagesCursor", msgCursorValue)):
msgCursor.setValue(msgCursorValue)
var messagesArr: JsonNode
var messages: seq[MessageDto]
if(responseObj.getProp("messages", messagesArr)):
messages = map(messagesArr.getElems(), proc(x: JsonNode): MessageDto = x.toMessageDto())
# handling reactions # handling reactions
var reactionsArr: JsonNode var reactionsArr: JsonNode
var reactions: seq[ReactionDto] var reactions: seq[ReactionDto]
@ -434,7 +474,6 @@ QtObject:
let data = MessagesLoadedArgs(chatId: chatId, let data = MessagesLoadedArgs(chatId: chatId,
messages: messages, messages: messages,
pinnedMessages: pinnedMessages,
reactions: reactions) reactions: reactions)
self.events.emit(SIGNAL_MESSAGES_LOADED, data) self.events.emit(SIGNAL_MESSAGES_LOADED, data)