From 964aa7ebc970c513de838e9708f05757eda9fa6e Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 9 Mar 2023 16:13:09 -0500 Subject: [PATCH] refactor(community): make community data calls async Fixes #9825 --- .../modules/main/communities/controller.nim | 3 + .../modules/main/communities/io_interface.nim | 3 + src/app/modules/main/communities/module.nim | 5 +- src/app/modules/main/controller.nim | 16 +++ src/app/modules/main/io_interface.nim | 17 +++ src/app/modules/main/module.nim | 42 +++++++ .../service/community/async_tasks.nim | 26 +++++ .../service/community/dto/community.nim | 8 +- src/app_service/service/community/service.nim | 106 ++++++++---------- 9 files changed, 161 insertions(+), 65 deletions(-) diff --git a/src/app/modules/main/communities/controller.nim b/src/app/modules/main/communities/controller.nim index 6680023772..cef8c94bb9 100644 --- a/src/app/modules/main/communities/controller.nim +++ b/src/app/modules/main/communities/controller.nim @@ -37,6 +37,9 @@ proc delete*(self: Controller) = discard proc init*(self: Controller) = + self.events.on(SIGNAL_COMMUNITY_DATA_LOADED) do(e:Args): + self.delegate.communityDataLoaded() + self.events.on(SIGNAL_COMMUNITY_CREATED) do(e:Args): let args = CommunityArgs(e) self.delegate.communityAdded(args.community) diff --git a/src/app/modules/main/communities/io_interface.nim b/src/app/modules/main/communities/io_interface.nim index a2157c9ac5..64358d4244 100644 --- a/src/app/modules/main/communities/io_interface.nim +++ b/src/app/modules/main/communities/io_interface.nim @@ -17,6 +17,9 @@ method isLoaded*(self: AccessInterface): bool {.base.} = method onActivated*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") +method communityDataLoaded*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + method setCommunityTags*(self: AccessInterface, communityTags: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index a602270c6d..e2e129b0fc 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -91,11 +91,12 @@ method isLoaded*(self: Module): bool = method viewDidLoad*(self: Module) = self.moduleLoaded = true + self.delegate.communitiesModuleDidLoad() + +method communityDataLoaded*(self: Module) = self.setCommunityTags(self.controller.getCommunityTags()) self.setAllCommunities(self.controller.getAllCommunities()) - self.delegate.communitiesModuleDidLoad() - method onActivated*(self: Module) = if self.curatedCommunitiesLoaded: return diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index b85a9ba18b..92e9991726 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -120,6 +120,22 @@ proc init*(self: Controller) = self.communityTokensService ) + self.events.on(SIGNAL_COMMUNITY_DATA_LOADED) do(e:Args): + self.delegate.onCommunityDataLoaded( + self.events, + self.settingsService, + self.nodeConfigurationService, + self.contactsService, + self.chatService, + self.communityService, + self.messageService, + self.gifService, + self.mailserversService, + self.walletAccountService, + self.tokenService, + self.communityTokensService + ) + self.events.on(SIGNAL_CHATS_LOADING_FAILED) do(e:Args): self.delegate.onChatsLoadingFailed() diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index 41bb1a8b9b..ae42007a2f 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -90,6 +90,23 @@ method onChatsLoaded*( {.base.} = raise newException(ValueError, "No implementation available") +method onCommunityDataLoaded*( + self: AccessInterface, + events: EventEmitter, + settingsService: settings_service.Service, + nodeConfigurationService: node_configuration_service.Service, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + gifService: gif_service.Service, + mailserversService: mailservers_service.Service, + walletAccountService: wallet_account_service.Service, + tokenService: token_service.Service, + communityTokensService: community_tokens_service.Service) + {.base.} = + raise newException(ValueError, "No implementation available") + method onChatsLoadingFailed*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 9b9d8956c4..4dbd64ad9a 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -99,6 +99,8 @@ type keycardSharedModule: keycard_shared_module.AccessInterface keycardSharedModuleKeycardSyncPurpose: keycard_shared_module.AccessInterface moduleLoaded: bool + chatsLoaded: bool + communityDataLoaded: bool statusUrlCommunityToSpectate: string # Forward declaration @@ -165,6 +167,8 @@ proc newModule*[T]( networkService ) result.moduleLoaded = false + result.chatsLoaded = false + result.communityDataLoaded = false result.events = events result.urlsManager = urlsManager @@ -534,6 +538,9 @@ method onChatsLoaded*[T]( tokenService: token_service.Service, communityTokensService: community_tokens_service.Service ) = + self.chatsLoaded = true + if not self.communityDataLoaded: + return var activeSection: SectionItem var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection() if activeSectionId == "": @@ -574,6 +581,41 @@ method onChatsLoaded*[T]( self.view.chatsLoaded() +method onCommunityDataLoaded*[T]( + self: Module[T], + events: EventEmitter, + settingsService: settings_service.Service, + nodeConfigurationService: node_configuration_service.Service, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + gifService: gif_service.Service, + mailserversService: mailservers_service.Service, + walletAccountService: wallet_account_service.Service, + tokenService: token_service.Service, + communityTokensService: community_tokens_service.Service +) = + self.communityDataLoaded = true + if not self.chatsLoaded: + return + + self.onChatsLoaded( + self.controller.getChannelGroups(), + events, + settingsService, + nodeConfigurationService, + contactsService, + chatService, + communityService, + messageService, + gifService, + mailserversService, + walletAccountService, + tokenService, + communityTokensService + ) + method onChatsLoadingFailed*[T](self: Module[T]) = self.view.chatsLoadingFailed() diff --git a/src/app_service/service/community/async_tasks.nim b/src/app_service/service/community/async_tasks.nim index dd9b788fdf..2613222b63 100644 --- a/src/app_service/service/community/async_tasks.nim +++ b/src/app_service/service/community/async_tasks.nim @@ -1,6 +1,32 @@ include ../../common/json_utils include ../../../app/core/tasks/common +type + AsyncLoadCommunitiesDataTaskArg = ref object of QObjectTaskArg + +const asyncLoadCommunitiesDataTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncLoadCommunitiesDataTaskArg](argEncoded) + try: + let responseTags = status_go.getCommunityTags() + + let responseCommunities = status_go.getAllCommunities() + + let responseSettings = status_go.getCommunitiesSettings() + + let responseMyPendingRequestsToJoin = status_go.myPendingRequestsToJoin() + + arg.finish(%* { + "tags": responseTags, + "communities": responseCommunities, + "settings": responseSettings, + "myPendingRequestsToJoin": responseMyPendingRequestsToJoin, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "error": e.msg, + }) + type AsyncRequestCommunityInfoTaskArg = ref object of QObjectTaskArg communityId: string diff --git a/src/app_service/service/community/dto/community.nim b/src/app_service/service/community/dto/community.nim index f26a6371c4..8be4d1c111 100644 --- a/src/app_service/service/community/dto/community.nim +++ b/src/app_service/service/community/dto/community.nim @@ -331,8 +331,8 @@ proc toCommunitySettingsDto*(jsonObj: JsonNode): CommunitySettingsDto = discard jsonObj.getProp("communityId", result.id) discard jsonObj.getProp("historyArchiveSupportEnabled", result.historyArchiveSupportEnabled) -proc parseCommunities*(response: RpcResponse[JsonNode]): seq[CommunityDto] = - result = map(response.result.getElems(), +proc parseCommunities*(response: JsonNode): seq[CommunityDto] = + result = map(response["result"].getElems(), proc(x: JsonNode): CommunityDto = x.toCommunityDto()) proc parseKnownCuratedCommunities(jsonCommunities: JsonNode): seq[CommunityDto] = @@ -391,8 +391,8 @@ proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto = encrypted: communityDto.encrypted, ) -proc parseCommunitiesSettings*(response: RpcResponse[JsonNode]): seq[CommunitySettingsDto] = - result = map(response.result.getElems(), +proc parseCommunitiesSettings*(response: JsonNode): seq[CommunitySettingsDto] = + result = map(response["result"].getElems(), proc(x: JsonNode): CommunitySettingsDto = x.toCommunitySettingsDto()) proc parseDiscordCategories*(response: RpcResponse[JsonNode]): seq[DiscordCategoryDto] = diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 15729546ee..278197f17d 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -110,6 +110,7 @@ type currentChunk*: int # Signals which may be emitted by this service: +const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded" const SIGNAL_COMMUNITY_JOINED* = "communityJoined" const SIGNAL_COMMUNITY_SPECTATED* = "communitySpectated" const SIGNAL_COMMUNITY_MY_REQUEST_ADDED* = "communityMyRequestAdded" @@ -177,11 +178,7 @@ QtObject: # Forward declaration proc loadCommunityTags(self: Service): string - proc loadAllCommunities(self: Service): seq[CommunityDto] proc asyncLoadCuratedCommunities*(self: Service) - proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto] - proc loadMyPendingRequestsToJoin*(self: Service) - proc loadMyCanceledRequestsToJoin*(self: Service) proc handleCommunityUpdates(self: Service, communities: seq[CommunityDto], updatedChats: seq[ChatDto], removedChats: seq[string]) proc handleCommunitiesSettingsUpdates(self: Service, communitiesSettings: seq[CommunitySettingsDto]) proc pendingRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] @@ -585,22 +582,55 @@ QtObject: proc init*(self: Service) = self.doConnect() - self.communityTags = self.loadCommunityTags(); - let communities = self.loadAllCommunities() - for community in communities: - self.communities[community.id] = community - if (community.admin): - self.communities[community.id].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id) - self.communities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id) - self.communities[community.id].canceledRequestsToJoin = self.canceledRequestsToJoinForCommunity(community.id) + try: + let arg = AsyncLoadCommunitiesDataTaskArg( + tptr: cast[ByteAddress](asyncLoadCommunitiesDataTask), + vptr: cast[ByteAddress](self.vptr), + slot: "asyncCommunitiesDataLoaded", + ) + self.threadpool.start(arg) + except Exception as e: + error "Error requesting communities data", msg = e.msg - let communitiesSettings = self.loadCommunitiesSettings() - for settings in communitiesSettings: - if self.communities.hasKey(settings.id): - self.communities[settings.id].settings = settings + proc asyncCommunitiesDataLoaded(self: Service, response: string) {.slot.} = + try: + let responseObj = response.parseJson + if (responseObj{"error"}.kind != JNull and responseObj{"error"}.getStr != ""): + error "error loading communities data", msg = responseObj{"error"}.getStr + return - self.loadMyPendingRequestsToJoin() + # Tags + var resultTags = newString(0) + toUgly(resultTags, responseObj["tags"]["result"]) + self.communityTags = resultTags + + # All communities + let communities = parseCommunities(responseObj["communities"]) + for community in communities: + self.communities[community.id] = community + if (community.admin): + self.communities[community.id].pendingRequestsToJoin = self.pendingRequestsToJoinForCommunity(community.id) + self.communities[community.id].declinedRequestsToJoin = self.declinedRequestsToJoinForCommunity(community.id) + self.communities[community.id].canceledRequestsToJoin = self.canceledRequestsToJoinForCommunity(community.id) + + # Communities settings + let communitiesSettings = parseCommunitiesSettings(responseObj["settings"]) + for settings in communitiesSettings: + if self.communities.hasKey(settings.id): + self.communities[settings.id].settings = settings + + # My pending requests + let myPendingRequestResponse = responseObj["myPendingRequestsToJoin"] + if myPendingRequestResponse{"result"}.kind != JNull: + for jsonCommunityReqest in myPendingRequestResponse["result"]: + let communityRequest = jsonCommunityReqest.toCommunityMembershipRequestDto() + self.myCommunityRequests.add(communityRequest) + + self.events.emit(SIGNAL_COMMUNITY_DATA_LOADED, Args()) + except Exception as e: + let errDesription = e.msg + error "error loading all communities: ", errDesription proc loadCommunityTags(self: Service): string = let response = status_go.getCommunityTags() @@ -608,24 +638,6 @@ QtObject: toUgly(result, response.result) return result - proc loadAllCommunities(self: Service): seq[CommunityDto] = - try: - let response = status_go.getAllCommunities() - return parseCommunities(response) - except Exception as e: - let errDesription = e.msg - error "error loading all communities: ", errDesription - return @[] - - proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto] = - try: - let response = status_go.getCommunitiesSettings() - return parseCommunitiesSettings(response) - except Exception as e: - let errDesription = e.msg - error "error loading communities settings: ", errDesription - return - proc getCommunityTags*(self: Service): string = return self.communityTags @@ -804,30 +816,6 @@ QtObject: except Exception as e: error "Error requesting to join the community", msg = e.msg, communityId, ensName - proc loadMyPendingRequestsToJoin*(self: Service) = - try: - let response = status_go.myPendingRequestsToJoin() - - if response.result.kind != JNull: - for jsonCommunityReqest in response.result: - let communityRequest = jsonCommunityReqest.toCommunityMembershipRequestDto() - self.myCommunityRequests.add(communityRequest) - self.events.emit(SIGNAL_COMMUNITY_MY_REQUEST_ADDED, CommunityRequestArgs(communityRequest: communityRequest)) - except Exception as e: - error "Error fetching my community requests", msg = e.msg - - proc loadMyCanceledRequestsToJoin*(self: Service) = - try: - let response = status_go.myCanceledRequestsToJoin() - - if response.result.kind != JNull: - for jsonCommunityReqest in response.result: - let communityRequest = jsonCommunityReqest.toCommunityMembershipRequestDto() - self.myCommunityRequests.add(communityRequest) - self.events.emit(SIGNAL_COMMUNITY_MY_REQUEST_ADDED, CommunityRequestArgs(communityRequest: communityRequest)) - except Exception as e: - error "Error fetching my community requests", msg = e.msg - proc canceledRequestsToJoinForCommunity*(self: Service, communityId: string): seq[CommunityMembershipRequestDto] = try: let response = status_go.canceledRequestsToJoinForCommunity(communityId)