From f0744ed61d339f645a942adbc6429421b15cc122 Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Tue, 29 Nov 2022 15:33:35 -0300 Subject: [PATCH] fix(@desktop/wallet) make collection expansion more responsive Collection fetch is now non-blocking Fixes #8406 --- .../collectibles/collectibles/controller.nim | 12 ++- .../collectibles/io_interface.nim | 6 +- .../collectibles/collectibles/module.nim | 9 +- .../wallet_section/collectibles/module.nim | 2 +- .../service/collectible/async_tasks.nim | 35 ++++++-- .../service/collectible/service.nim | 85 +++++++++++++++---- 6 files changed, 118 insertions(+), 31 deletions(-) diff --git a/src/app/modules/main/wallet_section/collectibles/collectibles/controller.nim b/src/app/modules/main/wallet_section/collectibles/collectibles/controller.nim index f2da0f0c04..7a844fab4a 100644 --- a/src/app/modules/main/wallet_section/collectibles/collectibles/controller.nim +++ b/src/app/modules/main/wallet_section/collectibles/collectibles/controller.nim @@ -1,25 +1,31 @@ import io_interface import ../../../../../../app_service/service/collectible/service as collectible_service +import ../../../../../core/eventemitter type Controller* = ref object of RootObj delegate: io_interface.AccessInterface + events: EventEmitter collectibleService: collectible_service.Service proc newController*( delegate: io_interface.AccessInterface, + events: EventEmitter, collectibleService: collectible_service.Service ): Controller = result = Controller() result.delegate = delegate + result.events = events result.collectibleService = collectibleService proc delete*(self: Controller) = discard proc init*(self: Controller) = - discard + self.events.on(GetCollectibles) do(e:Args): + let args = GetCollectiblesArgs(e) + self.delegate.setCollectibles(args.collectionSlug, args.collectibles) -proc fetch*(self: Controller, address: string, collectionSlug: string): seq[collectible_service.CollectibleDto] = - return self.collectibleService.getCollectibles(address, collectionSlug) +proc fetch*(self: Controller, address: string, collectionSlug: string) = + self.collectibleService.getCollectiblesAsync(address, collectionSlug) diff --git a/src/app/modules/main/wallet_section/collectibles/collectibles/io_interface.nim b/src/app/modules/main/wallet_section/collectibles/collectibles/io_interface.nim index c4f87902cb..ab6cf94fe7 100644 --- a/src/app/modules/main/wallet_section/collectibles/collectibles/io_interface.nim +++ b/src/app/modules/main/wallet_section/collectibles/collectibles/io_interface.nim @@ -1,3 +1,4 @@ +import ../../../../../../app_service/service/collectible/service as collectible_service import ./item type @@ -13,10 +14,13 @@ method load*(self: AccessInterface) {.base.} = method isLoaded*(self: AccessInterface): bool {.base.} = raise newException(ValueError, "No implementation available") +method setCurrentAddress*(self: AccessInterface, address: string) {.base.} = + raise newException(ValueError, "No implementation available") + method fetch*(self: AccessInterface, collectionSlug: string) {.base.} = raise newException(ValueError, "No implementation available") -method setCurrentAddress*(self: AccessInterface, address: string) {.base.} = +method setCollectibles*(self: AccessInterface, collectionSlug: string, collectibles: seq[CollectibleDto]) {.base.} = raise newException(ValueError, "No implementation available") method getCollectible*(self: AccessInterface, collectionSlug: string, id: int) : Item {.base.} = diff --git a/src/app/modules/main/wallet_section/collectibles/collectibles/module.nim b/src/app/modules/main/wallet_section/collectibles/collectibles/module.nim index 71ecf4a2f0..71b4be7fe8 100644 --- a/src/app/modules/main/wallet_section/collectibles/collectibles/module.nim +++ b/src/app/modules/main/wallet_section/collectibles/collectibles/module.nim @@ -4,6 +4,7 @@ import ../../../../../global/global_singleton import ./io_interface, ./view, ./controller, ./item import ../io_interface as delegate_interface import ../../../../../../app_service/service/collectible/service as collectible_service +import ../../../../../core/eventemitter export io_interface @@ -15,12 +16,12 @@ type moduleLoaded: bool currentAddress: string -proc newModule*(delegate: delegate_interface.AccessInterface, collectibleService: collectible_service.Service): +proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, collectibleService: collectible_service.Service): Module = result = Module() result.delegate = delegate result.view = newView(result) - result.controller = controller.newController(result, collectibleService) + result.controller = controller.newController(result, events, collectibleService) result.moduleLoaded = false method delete*(self: Module) = @@ -43,7 +44,9 @@ method setCurrentAddress*(self: Module, address: string) = self.currentAddress = address method fetch*(self: Module, collectionSlug: string) = - let collectibles = self.controller.fetch(self.currentAddress, collectionSlug) + self.controller.fetch(self.currentAddress, collectionSlug) + +method setCollectibles*(self: Module, collectionSlug: string, collectibles: seq[CollectibleDto]) = let items = collectibles.map(c => initItem( c.id, c.name, diff --git a/src/app/modules/main/wallet_section/collectibles/module.nim b/src/app/modules/main/wallet_section/collectibles/module.nim index c1f22f5ac6..044a7a5c1d 100644 --- a/src/app/modules/main/wallet_section/collectibles/module.nim +++ b/src/app/modules/main/wallet_section/collectibles/module.nim @@ -31,7 +31,7 @@ proc newModule*( result.controller = newController(result, walletAccountService) result.moduleLoaded = false - result.collectiblesModule = collectibles_module.newModule(result, collectibleService) + result.collectiblesModule = collectibles_module.newModule(result, events, collectibleService) result.collectionsModule = collectionsModule.newModule(result, events, collectibleService) result.currentCollectibleModule = currentCollectibleModule.newModule(result, collectibleService, result.collectionsModule, result.collectiblesModule) diff --git a/src/app_service/service/collectible/async_tasks.nim b/src/app_service/service/collectible/async_tasks.nim index 15b4729446..9b651a752c 100644 --- a/src/app_service/service/collectible/async_tasks.nim +++ b/src/app_service/service/collectible/async_tasks.nim @@ -5,13 +5,38 @@ type const getCollectionsTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = let arg = decode[GetCollectionsTaskArg](argEncoded) - + let output = %* { + "chainId": arg.chainId, + "address": arg.address, + "collections": "" + } try: let response = backend.getOpenseaCollectionsByOwner(arg.chainId, arg.address) - arg.finish(response.result) + output["collections"] = response.result except Exception as e: let errDesription = e.msg - error "error: ", errDesription - arg.finish("") + error "error getCollectionsTaskArg: ", errDesription + arg.finish(output) - \ No newline at end of file +type + GetCollectiblesTaskArg = ref object of QObjectTaskArg + chainId*: int + address*: string + collectionSlug: string + limit: int + +const getCollectiblesTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[GetCollectiblesTaskArg](argEncoded) + let output = %* { + "chainId": arg.chainId, + "address": arg.address, + "collectionSlug": arg.collectionSlug, + "collectibles": "" + } + try: + let response = backend.getOpenseaAssetsByOwnerAndCollection(arg.chainId, arg.address, arg.collectionSlug, arg.limit) + output["collectibles"] = response.result + except Exception as e: + let errDesription = e.msg + error "error getCollectiblesTaskArg: ", errDesription + arg.finish(output) diff --git a/src/app_service/service/collectible/service.nim b/src/app_service/service/collectible/service.nim index 71dc3311a5..b6d96f85b4 100644 --- a/src/app_service/service/collectible/service.nim +++ b/src/app_service/service/collectible/service.nim @@ -21,8 +21,20 @@ const GetCollections* = "get-collections" type GetCollectionsArgs* = ref object of Args + chainId*: int + address*: string collections*: seq[CollectionDto] +const GetCollectibles* = "get-collectibles" + +type + GetCollectiblesArgs* = ref object of Args + chainId*: int + address*: string + collectionSlug*: string + collectibles*: seq[CollectibleDto] + error*: string + QtObject: type Service* = ref object of QObject @@ -47,37 +59,74 @@ QtObject: proc init*(self: Service) = discard + proc getNetwork*(self: Service): NetworkDto = + return self.networkService.getNetworkForCollectibles() + proc onGetCollections*(self: Service, response: string) {.slot.} = + var data = GetCollectionsArgs() try: let responseObj = response.parseJson - if (responseObj.kind != JArray): - self.events.emit(GetCollections, GetCollectionsArgs()) - return - - let collections = map(responseObj.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto()) - self.events.emit(GetCollections, GetCollectionsArgs(collections: collections)) - except: - self.events.emit(GetCollections, GetCollectionsArgs()) + if (responseObj.kind == JObject): + let chainIdJson = responseObj["chainId"] + let addressJson = responseObj["address"] + + let validAccount = (chainIdJson.kind == JInt and + addressJson.kind == JString) + if (validAccount): + data.chainId = chainIdJson.getInt() + data.address = addressJson.getStr() + + let collectionsJson = responseObj["collections"] + if (collectionsJson.kind == JArray): + data.collections = map(collectionsJson.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto()) + except Exception as e: + let errDesription = e.msg + error "error onGetCollections: ", errDesription + self.events.emit(GetCollections, data) proc getCollectionsAsync*(self: Service, address: string) = let arg = GetCollectionsTaskArg( tptr: cast[ByteAddress](getCollectionsTaskArg), vptr: cast[ByteAddress](self.vptr), slot: "onGetCollections", - chainId: self.networkService.getNetworkForCollectibles().chainId, + chainId: self.getNetwork().chainId, address: address, ) self.threadpool.start(arg) - - proc getNetwork*(self: Service): NetworkDto = - return self.networkService.getNetworkForCollectibles() - proc getCollectibles*(self: Service, address: string, collectionSlug: string): seq[CollectibleDto] = + proc onGetCollectibles*(self: Service, response: string) {.slot.} = + var data = GetCollectiblesArgs() try: - let chainId = self.getNetwork().chainId - let response = backend.getOpenseaAssetsByOwnerAndCollection(chainId, address, collectionSlug, limit) - return map(response.result.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto()) + let responseObj = response.parseJson + if (responseObj.kind == JObject): + let chainIdJson = responseObj["chainId"] + let addressJson = responseObj["address"] + let collectionSlugJson = responseObj["collectionSlug"] + + let validCollection = (chainIdJson.kind == JInt and + addressJson.kind == JString and + collectionSlugJson.kind == JString) + if (validCollection): + data.chainId = chainIdJson.getInt() + data.address = addressJson.getStr() + data.collectionSlug = collectionSlugJson.getStr() + + let collectiblesJson = responseObj["collectibles"] + if (collectiblesJson.kind == JArray): + data.collectibles = map(collectiblesJson.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto()) except Exception as e: let errDesription = e.msg - error "error: ", errDesription - return + error "error onGetCollectibles: ", errDesription + self.events.emit(GetCollectibles, data) + + proc getCollectiblesAsync*(self: Service, address: string, collectionSlug: string) = + let arg = GetCollectiblesTaskArg( + tptr: cast[ByteAddress](getCollectiblesTaskArg), + vptr: cast[ByteAddress](self.vptr), + slot: "onGetCollectibles", + chainId: self.getNetwork().chainId, + address: address, + collectionSlug: collectionSlug, + limit: limit + ) + self.threadpool.start(arg)