Skip to content

Commit

Permalink
Merge pull request #1171 from novasamatech/base/network-management-im…
Browse files Browse the repository at this point in the history
…provements

Base/network management improvements
  • Loading branch information
svojsu authored Jul 31, 2024
2 parents cc490ae + a7af290 commit 8b85444
Show file tree
Hide file tree
Showing 46 changed files with 603 additions and 186 deletions.
2 changes: 2 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
disabled_rules:
- switch_case_alignment
excluded:
- Pods
- PrivatePods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class NewReferendumHandler: CommonHandler, PushNotificationHandler {

func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
) {
let chainOperation = chainsRepository.fetchAllOperation(with: .init())

Expand All @@ -32,19 +32,24 @@ final class NewReferendumHandler: CommonHandler, PushNotificationHandler {
backingCallIn: callStore,
runningCallbackIn: callbackQueue
) { [weak self] result in
guard let self = self else {
guard let self else {
return
}

switch result {
case let .success(chains):
guard
let chain = self.search(
chainId: self.chainId,
let chain = search(
chainId: chainId,
in: chains
),
chain.syncMode.enabled()
)
else {
completion(nil)
completion(.original(.chainNotFound(chainId: chainId)))
return
}

guard chain.syncMode.enabled() else {
completion(.filteredOut)
return
}

Expand All @@ -57,9 +62,14 @@ final class NewReferendumHandler: CommonHandler, PushNotificationHandler {
self.payload.referendumNumber,
preferredLanguages: self.locale.rLanguages
)
completion(.init(title: title, subtitle: subtitle))
case .failure:
completion(nil)

let notificationContentResult: NotificationContentResult = .init(
title: title,
subtitle: subtitle
)
completion(.modified(notificationContentResult))
case let .failure(error):
completion(.original(.internalError(error: error)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class ReferendumUpdatesHandler: CommonHandler, PushNotificationHandler {

func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
) {
let chainOperation = chainsRepository.fetchAllOperation(with: .init())

Expand All @@ -30,23 +30,25 @@ final class ReferendumUpdatesHandler: CommonHandler, PushNotificationHandler {
inOperationQueue: operationQueue,
runningCallbackIn: callbackQueue
) { [weak self] result in
guard let self = self else {
guard let self else {
return
}
switch result {
case let .success(chains):
guard
let chain = self.search(chainId: self.chainId, in: chains),
chain.syncMode.enabled()
else {
completion(nil)
guard let chain = search(chainId: chainId, in: chains) else {
completion(.original(.chainNotFound(chainId: chainId)))
return
}

guard chain.syncMode.enabled() else {
completion(.filteredOut)
return
}

let content = self.content(from: chain)
completion(content)
case .failure:
completion(nil)
completion(.modified(content))
case let .failure(error):
completion(.original(.internalError(error: error)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import Foundation
import SoraFoundation

enum PushNotificationHandleResult {
case modified(NotificationContentResult)
case filteredOut
case original(PushNotificationsHandlerErrors)
}

protocol PushNotificationHandler {
func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
)
}

Expand Down Expand Up @@ -52,3 +58,49 @@ final class PushNotificationHandlersFactory: PushNotificationHandlersFactoryProt
}
}
}

// MARK: Errors

enum PushNotificationsHandlerErrors: Error, Hashable {
static func == (
lhs: PushNotificationsHandlerErrors,
rhs: PushNotificationsHandlerErrors
) -> Bool {
switch (lhs, rhs) {
case (.chainDisabled, .chainDisabled):
return true
case let (.chainNotFound(lhsChainId), .chainNotFound(rhsChainId)):
return lhsChainId == rhsChainId
case let (.assetNotFound(lhsAssetId), .assetNotFound(rhsAssetId)):
return lhsAssetId == rhsAssetId
case let (.internalError(lhsError), .internalError(rhsError)):
return lhsError.localizedDescription == rhsError.localizedDescription
default:
return false
}
}

func hash(into hasher: inout Hasher) {
switch self {
case .chainDisabled:
hasher.combine(0)
case let .chainNotFound(chainId):
hasher.combine(1)
hasher.combine(chainId)
case let .assetNotFound(assetId):
hasher.combine(2)
hasher.combine(assetId)
case let .internalError(error):
hasher.combine(3)
hasher.combine(error.localizedDescription)
case .undefined:
hasher.combine(4)
}
}

case chainDisabled
case chainNotFound(chainId: ChainModel.Id)
case assetNotFound(assetId: String?)
case internalError(error: Error)
case undefined
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,39 @@ final class StakingRewardsHandler: CommonHandler, PushNotificationHandler {

func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
) {
let settingsOperation = settingsRepository.fetchAllOperation(with: .init())
let chainOperation = chainsRepository.fetchAllOperation(with: .init())

let contentWrapper: CompoundOperationWrapper<NotificationContentResult?> =
OperationCombiningService.compoundWrapper(
operationManager: OperationManager(operationQueue: operationQueue)) {
let contentWrapper: CompoundOperationWrapper<NotificationContentResult> =
OperationCombiningService.compoundNonOptionalWrapper(
operationManager: OperationManager(operationQueue: operationQueue)
) { [weak self] in
guard let self else {
throw PushNotificationsHandlerErrors.undefined
}

let settings = try settingsOperation.extractNoCancellableResultData().first
let chains = try chainOperation.extractNoCancellableResultData()
guard
let chain = self.search(chainId: self.chainId, in: chains),
chain.syncMode.enabled(),
let asset = chain.utilityAsset()
else {
return nil

guard let chain = self.search(chainId: chainId, in: chains) else {
throw PushNotificationsHandlerErrors.chainNotFound(chainId: chainId)
}

guard let asset = chain.utilityAsset() else {
throw PushNotificationsHandlerErrors.assetNotFound(assetId: chainId)
}

guard chain.syncMode.enabled() else {
throw PushNotificationsHandlerErrors.chainDisabled
}

let priceOperation: BaseOperation<[PriceData]>
if let priceId = asset.priceId,
let currency = self.currencyManager(operationQueue: self.operationQueue)?.selectedCurrency {
priceOperation = self.priceRepository(for: priceId, currencyId: currency.id).fetchAllOperation(with: .init())
if
let priceId = asset.priceId,
let currency = currencyManager(operationQueue: self.operationQueue)?.selectedCurrency {
priceOperation = priceRepository(for: priceId, currencyId: currency.id).fetchAllOperation(with: .init())
} else {
priceOperation = .createWithResult([])
}
Expand All @@ -53,6 +64,7 @@ final class StakingRewardsHandler: CommonHandler, PushNotificationHandler {
let mapOperaion = ClosureOperation {
let price = try priceOperation.extractNoCancellableResultData().first
let metaAccounts = try fetchMetaAccountsOperation.extractNoCancellableResultData()

return self.updatingContent(
wallets: settings?.wallets ?? [],
metaAccounts: metaAccounts,
Expand All @@ -79,9 +91,13 @@ final class StakingRewardsHandler: CommonHandler, PushNotificationHandler {
) { result in
switch result {
case let .success(content):
completion(content)
case .failure:
completion(nil)
completion(.modified(content))
case let .failure(error as PushNotificationsHandlerErrors) where error == .chainDisabled:
completion(.filteredOut)
case let .failure(error as PushNotificationsHandlerErrors):
completion(.original(error))
case let .failure(error):
completion(.original(.internalError(error: error)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class NewReleaseHandler: PushNotificationHandler {

func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
) {
dispatchInQueueWhenPossible(callbackQueue) {
let locale = self.localizationManager.selectedLocale
Expand All @@ -31,7 +31,12 @@ final class NewReleaseHandler: PushNotificationHandler {
preferredLanguages: locale.rLanguages
)

completion(.init(title: title, subtitle: subtitle))
let notificationConentResult: NotificationContentResult = .init(
title: title,
subtitle: subtitle
)

completion(.modified(notificationConentResult))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,44 @@ final class TransferHandler: CommonHandler, PushNotificationHandler {

func handle(
callbackQueue: DispatchQueue?,
completion: @escaping (NotificationContentResult?) -> Void
completion: @escaping (PushNotificationHandleResult) -> Void
) {
let settingsOperation = settingsRepository.fetchAllOperation(with: .init())
let chainOperation = chainsRepository.fetchAllOperation(with: .init())

let contentWrapper: CompoundOperationWrapper<NotificationContentResult?> =
OperationCombiningService.compoundWrapper(
operationManager: OperationManager(operationQueue: operationQueue)) {
let contentWrapper: CompoundOperationWrapper<NotificationContentResult> =
OperationCombiningService.compoundNonOptionalWrapper(
operationManager: OperationManager(operationQueue: operationQueue)
) { [weak self] in
guard let self else {
return .createWithError(PushNotificationsHandlerErrors.undefined)
}

let settings = try settingsOperation.extractNoCancellableResultData().first
let chains = try chainOperation.extractNoCancellableResultData()
guard
let chain = self.search(chainId: self.chainId, in: chains),
chain.syncMode.enabled(),
let asset = self.mapHistoryAssetId(self.payload.assetId, chain: chain)
else {
return nil

guard let chain = search(chainId: chainId, in: chains) else {
throw PushNotificationsHandlerErrors.chainNotFound(chainId: chainId)
}

guard let asset = mapHistoryAssetId(payload.assetId, chain: chain) else {
throw PushNotificationsHandlerErrors.assetNotFound(assetId: chainId)
}

guard chain.syncMode.enabled() else {
throw PushNotificationsHandlerErrors.chainDisabled
}

let priceOperation: BaseOperation<[PriceData]>
if let priceId = asset.priceId,
let currency = self.currencyManager(operationQueue: self.operationQueue)?.selectedCurrency {
priceOperation = self.priceRepository(for: priceId, currencyId: currency.id)
let currency = currencyManager(operationQueue: operationQueue)?.selectedCurrency {
priceOperation = priceRepository(for: priceId, currencyId: currency.id)
.fetchAllOperation(with: .init())
} else {
priceOperation = .createWithResult([])
}
priceOperation.addDependency(chainOperation)
let fetchMetaAccountsOperation = self.walletsRepository().fetchAllOperation(with: .init())
let fetchMetaAccountsOperation = walletsRepository().fetchAllOperation(with: .init())

let mapOperaion = ClosureOperation {
let price = try priceOperation.extractNoCancellableResultData().first
Expand Down Expand Up @@ -83,9 +93,13 @@ final class TransferHandler: CommonHandler, PushNotificationHandler {
) { result in
switch result {
case let .success(content):
completion(content)
case .failure:
completion(nil)
completion(.modified(content))
case let .failure(error as PushNotificationsHandlerErrors) where error == .chainDisabled:
completion(.filteredOut)
case let .failure(error as PushNotificationsHandlerErrors):
completion(.original(error))
case let .failure(error):
completion(.original(.internalError(error: error)))
}
}
}
Expand Down
28 changes: 25 additions & 3 deletions NovaPushNotificationServiceExtension/NotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ final class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
var handler: PushNotificationHandler?
var logger = Logger.shared

override func didReceive(
_ request: UNNotificationRequest,
Expand All @@ -33,10 +34,16 @@ final class NotificationService: UNNotificationServiceExtension {
let factory = PushNotificationHandlersFactory()
handler = factory.createHandler(message: message)

handler?.handle(callbackQueue: nil) { notification in
if let notification = notification {
handler?.handle(callbackQueue: nil) { [weak self] handlerResult in
switch handlerResult {
case let .modified(notification):
contentHandler(notification.toUserNotificationContent(with: bestAttemptContent))
} else {
case .filteredOut:
self?.logger.info("Notification skipped")
return
case let .original(error):
self?.logError(error)

let unsupported = NotificationContentResult.createUnsupportedResult(
for: LocalizationManager.shared.selectedLocale
)
Expand All @@ -51,4 +58,19 @@ final class NotificationService: UNNotificationServiceExtension {
contentHandler(bestAttemptContent)
}
}

private func logError(_ error: PushNotificationsHandlerErrors) {
switch error {
case let .assetNotFound(assetId):
logger.error("Notification handler failed to find asset with id: \(assetId ?? "")")
case let .chainNotFound(chainId):
logger.error("Notification handler failed to find asset with id: \(chainId)")
case let .internalError(error):
logger.error("Notification handler failed with error: \(error.localizedDescription)")
case .undefined:
logger.error("Notification handler failed with undefined reason")
default:
break
}
}
}
Loading

0 comments on commit 8b85444

Please sign in to comment.