From e0605bc1800dbd0c7c36b0e5e08e5d7db3aeae97 Mon Sep 17 00:00:00 2001 From: Krypto Pank Date: Sat, 12 Mar 2022 17:25:38 +0200 Subject: [PATCH] Delay subscribing for tokens updates for events creating #4066 --- AlphaWallet/InCoordinator.swift | 34 ++++++------------- .../Coordinators/EventSourceCoordinator.swift | 30 ++++++++++------ .../EventSourceCoordinatorForActivities.swift | 19 ++++++++--- .../Coordinators/TokensCoordinator.swift | 8 ++++- 4 files changed, 53 insertions(+), 38 deletions(-) diff --git a/AlphaWallet/InCoordinator.swift b/AlphaWallet/InCoordinator.swift index c470361b5..7f496aecb 100644 --- a/AlphaWallet/InCoordinator.swift +++ b/AlphaWallet/InCoordinator.swift @@ -32,7 +32,10 @@ class InCoordinator: NSObject, Coordinator { private let queue: DispatchQueue = DispatchQueue(label: "com.Background.updateQueue", qos: .userInitiated) lazy private var eventsDataStore: NonActivityEventsDataStore = NonActivityMultiChainEventsDataStore(realm: realm) lazy private var eventsActivityDataStore: EventsActivityDataStoreProtocol = EventsActivityDataStore(realm: realm) - private var eventSourceCoordinatorForActivities: EventSourceCoordinatorForActivities? + private lazy var eventSourceCoordinatorForActivities: EventSourceCoordinatorForActivities? = { + guard Features.isActivityEnabled else { return nil } + return EventSourceCoordinatorForActivities(wallet: wallet, config: config, tokensDataStore: tokensDataStore, assetDefinitionStore: assetDefinitionStore, eventsDataStore: eventsActivityDataStore) + }() private let coinTickersFetcher: CoinTickersFetcherType lazy var tokensDataStore: TokensDataStore = { @@ -150,7 +153,6 @@ class InCoordinator: NSObject, Coordinator { //Disabled for now. Refer to function's comment //self.assetDefinitionStore.enableFetchXMLForContractInPasteboard() super.init() - } deinit { @@ -214,9 +216,7 @@ class InCoordinator: NSObject, Coordinator { guard let token = tokensDataStore.token(forContract: contract, server: server) else { return } eventsDataStore.deleteEvents(forTokenContract: contract) let _ = eventSourceCoordinator.fetchEventsByTokenId(forToken: token) - if Features.isActivityEnabled { - let _ = eventSourceCoordinatorForActivities?.fetchEvents(forToken: token) - } + let _ = eventSourceCoordinatorForActivities?.fetchEvents(forToken: token) } private func oneTimeCreationOfOneDatabaseToHoldAllChains() { @@ -263,23 +263,6 @@ class InCoordinator: NSObject, Coordinator { setUpEventSourceCoordinatorForActivities() } - private func fetchEthereumEvents() { - eventSourceCoordinator.fetchEthereumEvents() - if Features.isActivityEnabled { - eventSourceCoordinatorForActivities?.fetchEthereumEvents() - } - } - - private func pollEthereumEvents(tokensDataStore: TokensDataStore) { - tokensDataStore - .enabledTokenObjectsChangesetPublisher(forServers: config.enabledServers) - .subscribe(on: DispatchQueue.main) - .sink { [weak self] _ in - guard let strongSelf = self else { return } - strongSelf.fetchEthereumEvents() - }.store(in: &cancellable) - } - //Internal for test purposes /*private*/ func showTabBar(for account: Wallet, animated: Bool) { keystore.recentlyUsedWallet = account @@ -349,7 +332,6 @@ class InCoordinator: NSObject, Coordinator { private func createTokensCoordinator(promptBackupCoordinator: PromptBackupCoordinator, activitiesService: ActivitiesServiceType) -> TokensCoordinator { promptBackupCoordinator.listenToNativeCryptoCurrencyBalance(withWalletSessions: sessionsSubject.value) - pollEthereumEvents(tokensDataStore: tokensDataStore) let coordinator = TokensCoordinator( sessions: sessionsSubject.value, @@ -369,6 +351,7 @@ class InCoordinator: NSObject, Coordinator { coordinator.rootViewController.tabBarItem = UITabBarController.Tabs.tokens.tabBarItem coordinator.delegate = self coordinator.start() + addCoordinator(coordinator) return coordinator } @@ -999,6 +982,11 @@ extension InCoordinator: WhereAreMyTokensCoordinatorDelegate { extension InCoordinator: TokensCoordinatorDelegate { + func viewWillAppearOnce(in coordinator: TokensCoordinator) { + eventSourceCoordinator.start() + eventSourceCoordinatorForActivities?.start() + } + func whereAreMyTokensSelected(in coordinator: TokensCoordinator) { let coordinator = WhereAreMyTokensCoordinator(navigationController: navigationController) coordinator.delegate = self diff --git a/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinator.swift b/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinator.swift index 8bee02501..d9bf76e5c 100644 --- a/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinator.swift +++ b/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinator.swift @@ -4,6 +4,7 @@ import Foundation import BigInt import PromiseKit import web3swift +import Combine extension PromiseKit.Result { var optionalValue: T? { @@ -17,12 +18,13 @@ extension PromiseKit.Result { } protocol EventSourceCoordinatorType: class { - func fetchEthereumEvents() + func start() @discardableResult func fetchEventsByTokenId(forToken token: TokenObject) -> [Promise] } + //TODO: Create XMLHandler store and pass it everwhere we use it //TODO: Rename this generic name to reflect that it's for event instances, not for event activity -class EventSourceCoordinator: EventSourceCoordinatorType { +class EventSourceCoordinator: NSObject, EventSourceCoordinatorType { private var wallet: Wallet private let tokensDataStore: TokensDataStore private let assetDefinitionStore: AssetDefinitionStore @@ -31,6 +33,7 @@ class EventSourceCoordinator: EventSourceCoordinatorType { private var rateLimitedUpdater: RateLimiter? private let queue = DispatchQueue(label: "com.eventSourceCoordinator.updateQueue") private let enabledServers: [RPCServer] + private var cancellable = Set() init(wallet: Wallet, tokensDataStore: TokensDataStore, assetDefinitionStore: AssetDefinitionStore, eventsDataStore: NonActivityEventsDataStore, config: Config) { self.wallet = wallet @@ -38,6 +41,18 @@ class EventSourceCoordinator: EventSourceCoordinatorType { self.assetDefinitionStore = assetDefinitionStore self.eventsDataStore = eventsDataStore self.enabledServers = config.enabledServers + + super.init() + } + + func start() { + tokensDataStore + .enabledTokenObjectsChangesetPublisher(forServers: enabledServers) + .subscribe(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let strongSelf = self else { return } + strongSelf.fetchEthereumEvents() + }.store(in: &cancellable) } func fetchEventsByTokenId(forToken token: TokenObject) -> [Promise] { @@ -84,15 +99,10 @@ class EventSourceCoordinator: EventSourceCoordinatorType { seal.fulfill(values) } - } - //NOTE: calling .fetchEventsByTokenId shoul be performed on .main queue + } }.then(on: .main, { tokens -> Promise in - return Promise { seal in - let promises = tokens.map { self.fetchEventsByTokenId(forToken: $0) }.flatMap { $0 } - when(resolved: promises).done { _ in - seal.fulfill(()) - } - } + let promises = tokens.map { self.fetchEventsByTokenId(forToken: $0) }.flatMap { $0 } + return when(resolved: promises).asVoid() }).done(on: queue, { _ in self.isFetching = false }).cauterize() diff --git a/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinatorForActivities.swift b/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinatorForActivities.swift index 337183c47..129522e74 100644 --- a/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinatorForActivities.swift +++ b/AlphaWallet/TokenScriptClient/Coordinators/EventSourceCoordinatorForActivities.swift @@ -4,11 +4,11 @@ import Foundation import BigInt import PromiseKit import web3swift +import Combine protocol EventSourceCoordinatorForActivitiesType: AnyObject { - func fetchEvents(forToken token: TokenObject) -> [Promise] - func fetchEvents(contract: AlphaWallet.Address, tokenType: TokenType, rpcServer: RPCServer) -> [Promise] - func fetchEthereumEvents() + func fetchEvents(forToken token: TokenObject) -> [Promise] + func start() } class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesType { @@ -21,6 +21,7 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy private var rateLimitedUpdater: RateLimiter? private let queue = DispatchQueue(label: "com.EventSourceCoordinatorForActivities.updateQueue") private let enabledServers: [RPCServer] + private var cancellable = Set() init(wallet: Wallet, config: Config, tokensDataStore: TokensDataStore, assetDefinitionStore: AssetDefinitionStore, eventsDataStore: EventsActivityDataStoreProtocol) { self.wallet = wallet @@ -31,6 +32,16 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy self.enabledServers = Config().enabledServers } + func start() { + tokensDataStore + .enabledTokenObjectsChangesetPublisher(forServers: config.enabledServers) + .subscribe(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let strongSelf = self else { return } + strongSelf.fetchEthereumEvents() + }.store(in: &cancellable) + } + func fetchEvents(forToken token: TokenObject) -> [Promise] { let xmlHandler = XMLHandler(contract: token.contractAddress, tokenType: token.type, assetDefinitionStore: assetDefinitionStore) guard xmlHandler.hasAssetDefinition else { return [] } @@ -39,7 +50,7 @@ class EventSourceCoordinatorForActivities: EventSourceCoordinatorForActivitiesTy } } - func fetchEvents(contract: AlphaWallet.Address, tokenType: TokenType, rpcServer: RPCServer) -> [Promise] { + private func fetchEvents(contract: AlphaWallet.Address, tokenType: TokenType, rpcServer: RPCServer) -> [Promise] { let xmlHandler = XMLHandler(contract: contract, tokenType: tokenType, assetDefinitionStore: assetDefinitionStore) guard xmlHandler.hasAssetDefinition else { return [] } return xmlHandler.activityCards.compactMap { diff --git a/AlphaWallet/Tokens/Coordinators/TokensCoordinator.swift b/AlphaWallet/Tokens/Coordinators/TokensCoordinator.swift index 7c3c2cc37..c52c77e68 100644 --- a/AlphaWallet/Tokens/Coordinators/TokensCoordinator.swift +++ b/AlphaWallet/Tokens/Coordinators/TokensCoordinator.swift @@ -18,6 +18,7 @@ protocol TokensCoordinatorDelegate: CanOpenURL, SendTransactionDelegate { func whereAreMyTokensSelected(in coordinator: TokensCoordinator) func didSelectAccount(account: Wallet, in coordinator: TokensCoordinator) + func viewWillAppearOnce(in coordinator: TokensCoordinator) } private struct NoContractDetailsDetected: Error { @@ -101,7 +102,7 @@ class TokensCoordinator: Coordinator { private let tokensDataStore: TokensDataStore private let tokensAutoDetectionQueue: DispatchQueue = DispatchQueue(label: "com.TokensAutoDetection.updateQueue") - + private var viewWillAppearHandled = false init( navigationController: UINavigationController = .withOverridenBarAppearence(), sessions: ServerDictionary, @@ -264,6 +265,11 @@ extension TokensCoordinator: TokensViewControllerDelegate { func viewWillAppear(in viewController: UIViewController) { getWalletName() getWalletBlockie() + + guard !viewWillAppearHandled else { return } + viewWillAppearHandled = true + + delegate?.viewWillAppearOnce(in: self) } private func makeMoreAlertSheet(sender: UIBarButtonItem) -> UIAlertController {