From 0cd2419f595eb7d57f823d32e3fedf158af33089 Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Fri, 30 Dec 2022 21:26:46 +0100 Subject: [PATCH] fix(@desktop/chat): Improve installing stickers code to handle disconnected state better Use async task to install stickers Issue #6567 --- src/app/modules/main/stickers/controller.nim | 4 +++ .../modules/main/stickers/io_interface.nim | 3 +++ .../stickers/models/sticker_pack_list.nim | 13 +++++++++ src/app/modules/main/stickers/module.nim | 3 +++ src/app/modules/main/stickers/view.nim | 5 ++++ .../service/stickers/async_tasks.nim | 22 +++++++++++++++ src/app_service/service/stickers/service.nim | 27 ++++++++++++++----- .../shared/status/StatusStickersPopup.qml | 16 +++++++++-- 8 files changed, 85 insertions(+), 8 deletions(-) diff --git a/src/app/modules/main/stickers/controller.nim b/src/app/modules/main/stickers/controller.nim index 07e662df2f..b93f190556 100644 --- a/src/app/modules/main/stickers/controller.nim +++ b/src/app/modules/main/stickers/controller.nim @@ -107,6 +107,10 @@ proc init*(self: Controller) = return self.delegate.onUserAuthenticated(args.password) + self.events.on(SIGNAL_STICKER_PACK_INSTALLED) do(e: Args): + let args = StickerPackInstalledArgs(e) + self.delegate.onStickerPackInstalled(args.packId) + proc buy*(self: Controller, packId: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, eip1559Enabled: bool): tuple[response: string, success: bool] = self.stickerService.buy(packId, address, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, eip1559Enabled) diff --git a/src/app/modules/main/stickers/io_interface.nim b/src/app/modules/main/stickers/io_interface.nim index 7f3cd5ed9e..11ca5e60c4 100644 --- a/src/app/modules/main/stickers/io_interface.nim +++ b/src/app/modules/main/stickers/io_interface.nim @@ -49,6 +49,9 @@ method estimate*(self: AccessInterface, packId: string, address: string, price: method installStickerPack*(self: AccessInterface, packId: string) {.base.} = raise newException(ValueError, "No implementation available") +method onStickerPackInstalled*(self: AccessInterface, packId: string) {.base.} = + raise newException(ValueError, "No implementation available") + method uninstallStickerPack*(self: AccessInterface, packId: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/stickers/models/sticker_pack_list.nim b/src/app/modules/main/stickers/models/sticker_pack_list.nim index b5651793e5..3b7442a33d 100644 --- a/src/app/modules/main/stickers/models/sticker_pack_list.nim +++ b/src/app/modules/main/stickers/models/sticker_pack_list.nim @@ -26,6 +26,7 @@ QtObject: delegate: io_interface.AccessInterface packs*: seq[StickerPackView] packIdToRetrieve*: int + foundStickers*: QVariant proc setup(self: StickerPackList) = self.QAbstractListModel.setup @@ -123,6 +124,18 @@ QtObject: let packInfo = self.packs[self.packIdToRetrieve] result = newQVariant(packInfo.stickers) + # We cannot return QVariant from the proc which has arguments. + # First findStickersById has to be called, then getFoundStickers + proc findStickersById*(self: StickerPackList, packId: string) {.slot.} = + self.foundStickers = newQVariant() + for item in self.packs: + if(item.pack.id == packId): + self.foundStickers = newQVariant(item.stickers) + break + + proc getFoundStickers*(self: StickerPackList): QVariant {.slot.} = + return self.foundStickers + proc rowData*(self: StickerPackList, row: int, data: string): string {.slot.} = if row < 0 or (row > self.packs.len - 1): return diff --git a/src/app/modules/main/stickers/module.nim b/src/app/modules/main/stickers/module.nim index d338ab1a43..b09b31c940 100644 --- a/src/app/modules/main/stickers/module.nim +++ b/src/app/modules/main/stickers/module.nim @@ -137,6 +137,9 @@ method getNumInstalledStickerPacks*(self: Module): int = method installStickerPack*(self: Module, packId: string) = self.controller.installStickerPack(packId) +method onStickerPackInstalled*(self: Module, packId: string) = + self.view.onStickerPackInstalled(packId) + method uninstallStickerPack*(self: Module, packId: string) = self.controller.uninstallStickerPack(packId) diff --git a/src/app/modules/main/stickers/view.nim b/src/app/modules/main/stickers/view.nim index 348d3242e7..447c9cbc56 100644 --- a/src/app/modules/main/stickers/view.nim +++ b/src/app/modules/main/stickers/view.nim @@ -67,6 +67,8 @@ QtObject: proc stickerPacksLoaded*(self: View) {.signal.} + proc stickerPackInstalled*(self: View, packId: string) {.signal.} + proc packsLoadFailedChanged*(self: View) {.signal.} proc installedStickerPacksUpdated*(self: View) {.signal.} @@ -87,8 +89,11 @@ QtObject: proc install*(self: View, packId: string) {.slot.} = self.delegate.installStickerPack(packId) + + proc onStickerPackInstalled*(self:View, packId: string) = self.stickerPacks.updateStickerPackInList(packId, true, false) self.installedStickerPacksUpdated() + self.stickerPackInstalled(packId) proc resetBuyAttempt*(self: View, packId: string) {.slot.} = self.stickerPacks.updateStickerPackInList(packId, false, false) diff --git a/src/app_service/service/stickers/async_tasks.nim b/src/app_service/service/stickers/async_tasks.nim index 66ddf2387c..aa9a06a75c 100644 --- a/src/app_service/service/stickers/async_tasks.nim +++ b/src/app_service/service/stickers/async_tasks.nim @@ -10,6 +10,10 @@ type ObtainMarketStickerPacksTaskArg = ref object of QObjectTaskArg chainId*: int running*: ByteAddress # pointer to threadpool's `.running` Atomic[bool] + InstallStickerPackTaskArg = ref object of QObjectTaskArg + packId*: string + chainId*: int + hasKey*: bool proc getMarketStickerPacks*(running: var Atomic[bool], chainId: int): tuple[stickers: Table[string, StickerPackDto], error: string] = @@ -51,3 +55,21 @@ const obtainMarketStickerPacksTask: Task = proc(argEncoded: string) {.gcsafe, ni packs.add(stickerPack) let tpl: tuple[packs: seq[StickerPackDto], error: string] = (packs, error) arg.finish(tpl) + +const installStickerPackTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[InstallStickerPackTaskArg](argEncoded) + if not arg.hasKey: + arg.finish(false) + return + var installed = false + try: + let installResponse = status_stickers.install(arg.chainId, arg.packId) + if installResponse.error == nil: + installed = true + else: + let err = Json.decode($installResponse.error, RpcError) + error "Error installing stickers", message = err.message + except RpcException: + error "Error installing stickers", message = getCurrentExceptionMsg() + let tpl: tuple[packId: string, installed: bool] = (arg.packId, installed) + arg.finish(tpl) \ No newline at end of file diff --git a/src/app_service/service/stickers/service.nim b/src/app_service/service/stickers/service.nim index a5dd17b423..5eb44e4711 100644 --- a/src/app_service/service/stickers/service.nim +++ b/src/app_service/service/stickers/service.nim @@ -50,6 +50,8 @@ type packID*: string transactionType*: string revertReason*: string + StickerPackInstalledArgs* = ref object of Args + packId*: string # Signals which may be emitted by this service: const SIGNAL_STICKER_PACK_LOADED* = "stickerPackLoaded" @@ -58,6 +60,7 @@ const SIGNAL_ALL_STICKER_PACKS_LOAD_FAILED* = "allStickerPacksLoadFailed" const SIGNAL_STICKER_GAS_ESTIMATED* = "stickerGasEstimated" const SIGNAL_STICKER_TRANSACTION_CONFIRMED* = "stickerTransactionConfirmed" const SIGNAL_STICKER_TRANSACTION_REVERTED* = "stickerTransactionReverted" +const SIGNAL_STICKER_PACK_INSTALLED* = "stickerPackInstalled" QtObject: type Service* = ref object of QObject @@ -329,21 +332,33 @@ QtObject: for stickerJson in recentResponse.result: result = stickerJson.toStickerDto() & result except RpcException: - error "Error obtaining installed stickers", message = getCurrentExceptionMsg() + error "Error getting recent stickers", message = getCurrentExceptionMsg() proc getNumInstalledStickerPacks*(self: Service): int = try: let installedResponse = status_stickers.installed() return installedResponse.result.len except RpcException: - error "Error obtaining installed stickers", message = getCurrentExceptionMsg() + error "Error getting installed stickers number", message = getCurrentExceptionMsg() return 0 proc installStickerPack*(self: Service, packId: string) = - let chainId = self.networkService.getNetworkForStickers().chainId - if not self.marketStickerPacks.hasKey(packId): - return - let installResponse = status_stickers.install(chainId, packId) + let arg = InstallStickerPackTaskArg( + tptr: cast[ByteAddress](installStickerPackTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onStickerPackInstalled", + chainId: self.networkService.getNetworkForStickers().chainId, + packId: packId, + hasKey: self.marketStickerPacks.hasKey(packId) + ) + self.threadpool.start(arg) + + proc onStickerPackInstalled*(self: Service, installedPackJson: string) {.slot.} = + let installedPack = Json.decode(installedPackJson, tuple[packId: string, installed: bool]) + if installedPack.installed: + self.events.emit(SIGNAL_STICKER_PACK_INSTALLED, StickerPackInstalledArgs( + packId: installedPack.packId + )) proc uninstallStickerPack*(self: Service, packId: string) = try: diff --git a/ui/imports/shared/status/StatusStickersPopup.qml b/ui/imports/shared/status/StatusStickersPopup.qml index 4a74d55460..ce00154ea5 100644 --- a/ui/imports/shared/status/StatusStickersPopup.qml +++ b/ui/imports/shared/status/StatusStickersPopup.qml @@ -82,9 +82,8 @@ Popup { stickerPacks: d.stickerPackList packId: stickerPackListView.selectedPackId onInstallClicked: { + //starts async task stickersModule.install(packId) - stickerGrid.model = stickers - stickerPackListView.itemAt(index).clicked() } onUninstallClicked: { stickersModule.uninstall(packId) @@ -97,6 +96,19 @@ Popup { stickersContainer.visible = true } + Connections { + target: root.store.stickersModuleInst + function onStickerPackInstalled(packId) { + const idx = stickersModule.stickerPacks.findIndexById(packId, false); + if (idx === -1) { + return + } + stickersModule.stickerPacks.findStickersById(packId) + stickerGrid.model = stickersModule.stickerPacks.getFoundStickers() + stickerPackListView.itemAt(idx).clicked() + } + } + Loader { id: marketLoader anchors.centerIn: parent