From d1ffa2e3b3614c7ac7afc761fa2891fa74b35cd3 Mon Sep 17 00:00:00 2001 From: Alex Jbanca Date: Wed, 12 Apr 2023 12:50:42 +0300 Subject: [PATCH] perf(ChatLoadingTime): Separate get chat messages and get pinned messages in different tasks --- .../chat_section/chat_content/controller.nim | 4 +- .../chat_content/messages/controller.nim | 8 +- .../chat_content/messages/io_interface.nim | 6 +- .../chat_content/messages/module.nim | 12 +-- .../service/message/async_tasks.nim | 33 ++++--- src/app_service/service/message/service.nim | 91 +++++++++++++------ 6 files changed, 105 insertions(+), 49 deletions(-) diff --git a/src/app/modules/main/chat_section/chat_content/controller.nim b/src/app/modules/main/chat_section/chat_content/controller.nim index 457ed13915..79ec20be9b 100644 --- a/src/app/modules/main/chat_section/chat_content/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/controller.nim @@ -58,8 +58,8 @@ proc delete*(self: Controller) = self.events.disconnect() proc init*(self: Controller) = - self.events.on(SIGNAL_MESSAGES_LOADED) do(e:Args): - let args = MessagesLoadedArgs(e) + self.events.on(SIGNAL_PINNED_MESSAGES_LOADED) do(e:Args): + let args = PinnedMessagesLoadedArgs(e) if(self.chatId != args.chatId or args.pinnedMessages.len == 0): return self.delegate.newPinnedMessagesLoaded(args.pinnedMessages) diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller.nim b/src/app/modules/main/chat_section/chat_content/messages/controller.nim index 856b2336cb..38505bda00 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/controller.nim @@ -58,7 +58,13 @@ proc init*(self: Controller) = let args = MessagesLoadedArgs(e) if(self.chatId != args.chatId): 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): var args = MessagesArgs(e) diff --git a/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim b/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim index 184f1bff0e..bcad3266e4 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim @@ -25,8 +25,10 @@ method updateChatIdentifier*(self: AccessInterface) {.base.} = method updateChatFetchMoreMessages*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method newMessagesLoaded*(self: AccessInterface, messages: seq[MessageDto], reactions: seq[ReactionDto], - pinnedMessages: seq[PinnedMessageDto]) {.base.} = +method newMessagesLoaded*(self: AccessInterface, messages: seq[MessageDto], reactions: seq[ReactionDto]) {.base.} = + raise newException(ValueError, "No implementation available") + +method newPinnedMessagesLoaded*(self: AccessInterface, pinnedMessages: seq[PinnedMessageDto]) {.base.} = raise newException(ValueError, "No implementation available") method onReactionAdded*(self: AccessInterface, messageId: string, emojiId: int, reactionId: string) {.base.} = diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim index d772b7a7d9..931a0ff346 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/module.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim @@ -221,8 +221,7 @@ method reevaluateViewLoadingState*(self: Module) = not self.firstUnseenMessageState.initialized or self.firstUnseenMessageState.fetching) -method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto], - pinnedMessages: seq[PinnedMessageDto]) = +method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto]) = var viewItems: seq[Item] if(messages.len > 0): @@ -327,11 +326,6 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se else: 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: item.isEdited = true @@ -357,6 +351,10 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se self.initialMessagesLoaded = true 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]) = var items: seq[Item] diff --git a/src/app_service/service/message/async_tasks.nim b/src/app_service/service/message/async_tasks.nim index e00c7daa35..ff09e9e36c 100644 --- a/src/app_service/service/message/async_tasks.nim +++ b/src/app_service/service/message/async_tasks.nim @@ -12,7 +12,6 @@ type AsyncFetchChatMessagesTaskArg = ref object of QObjectTaskArg chatId: string msgCursor: string - pinnedMsgCursor: string limit: int const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = @@ -32,16 +31,6 @@ const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimc responseJson["messages"] = messagesArr 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 if(arg.msgCursor != CURSOR_VALUE_IGNORE): # messages and reactions are using the same cursor @@ -52,6 +41,28 @@ const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimc 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 ################################################# diff --git a/src/app_service/service/message/service.nim b/src/app_service/service/message/service.nim index 753a746f9d..b5135f8ed9 100644 --- a/src/app_service/service/message/service.nim +++ b/src/app_service/service/message/service.nim @@ -40,6 +40,7 @@ const WEEK_AS_MILLISECONDS = initDuration(seconds = 60*60*24*7).inMilliSeconds # Signals which may be emitted by this service: const SIGNAL_MESSAGES_LOADED* = "messagesLoaded" +const SIGNAL_PINNED_MESSAGES_LOADED* = "pinnedMessagesLoaded" const SIGNAL_FIRST_UNSEEN_MESSAGE_LOADED* = "firstUnseenMessageLoaded" const SIGNAL_NEW_MESSAGE_RECEIVED* = "newMessageReceived" const SIGNAL_MESSAGE_PINNED* = "messagePinned" @@ -72,9 +73,12 @@ type MessagesLoadedArgs* = ref object of Args chatId*: string messages*: seq[MessageDto] - pinnedMessages*: seq[PinnedMessageDto] reactions*: seq[ReactionDto] + PinnedMessagesLoadedArgs* = ref object of Args + chatId*: string + pinnedMessages*: seq[PinnedMessageDto] + MessagePinUnpinArgs* = ref object of Args chatId*: string messageId*: string @@ -188,16 +192,11 @@ QtObject: let msgCursor = self.initOrGetMessageCursor(chatId) let msgCursorValue = if (msgCursor.isFetchable()): msgCursor.getValue() else: CURSOR_VALUE_IGNORE - let pinnedMsgCursor = self.initOrGetPinnedMessageCursor(chatId) - let pinnedMsgCursorValue = if (pinnedMsgCursor.isFetchable()): pinnedMsgCursor.getValue() else: CURSOR_VALUE_IGNORE - - if(msgCursorValue == CURSOR_VALUE_IGNORE and pinnedMsgCursorValue == CURSOR_VALUE_IGNORE): + if(msgCursorValue == CURSOR_VALUE_IGNORE): return if(msgCursorValue != CURSOR_VALUE_IGNORE): msgCursor.setPending() - if (pinnedMsgCursorValue != CURSOR_VALUE_IGNORE): - pinnedMsgCursor.setPending() let arg = AsyncFetchChatMessagesTaskArg( tptr: cast[ByteAddress](asyncFetchChatMessagesTask), @@ -205,17 +204,39 @@ QtObject: slot: "onAsyncLoadMoreMessagesForChat", chatId: chatId, msgCursor: msgCursorValue, - pinnedMsgCursor: pinnedMsgCursorValue, limit: if(limit <= MESSAGES_PER_PAGE_MAX): limit else: MESSAGES_PER_PAGE_MAX ) 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) = if(self.isChatCursorInitialized(chatId)): let data = MessagesLoadedArgs(chatId: chatId, messages: @[], - pinnedMessages: @[], reactions: @[]) self.events.emit(SIGNAL_MESSAGES_LOADED, data) @@ -389,30 +410,17 @@ QtObject: weiStr.trimZeros() return (tokenStr, weiStr) - proc onAsyncLoadMoreMessagesForChat*(self: Service, response: string) {.slot.} = + proc onAsyncLoadPinnedMessagesForChat*(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()) + info "load pinned messages response is not a json object" + self.events.emit(SIGNAL_PINNED_MESSAGES_LOADED, PinnedMessagesLoadedArgs()) return var chatId: string discard responseObj.getProp("chatId", chatId) - let msgCursor = self.initOrGetMessageCursor(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 var pinnedMsgCursorValue: string if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursorValue)): @@ -426,6 +434,38 @@ QtObject: # set initial number of pinned messages 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 var reactionsArr: JsonNode var reactions: seq[ReactionDto] @@ -434,7 +474,6 @@ QtObject: let data = MessagesLoadedArgs(chatId: chatId, messages: messages, - pinnedMessages: pinnedMessages, reactions: reactions) self.events.emit(SIGNAL_MESSAGES_LOADED, data)