Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Notify] Subscriptions Updater #1256

Merged
merged 4 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class NotifyClient {
return logger.logsPublisher
}

private let deleteNotifySubscriptionRequester: DeleteNotifySubscriptionRequester
private let notifyDeleteSubscriptionRequester: NotifyDeleteSubscriptionRequester
private let notifySubscribeRequester: NotifySubscribeRequester

public let logger: ConsoleLogging
Expand All @@ -31,12 +31,14 @@ public class NotifyClient {
private let notifyMessageSubscriber: NotifyMessageSubscriber
private let resubscribeService: NotifyResubscribeService
private let notifySubscribeResponseSubscriber: NotifySubscribeResponseSubscriber
private let notifyDeleteSubscriptionSubscriber: NotifyDeleteSubscriptionSubscriber
private let notifyUpdateRequester: NotifyUpdateRequester
private let notifyUpdateResponseSubscriber: NotifyUpdateResponseSubscriber
private let subscriptionsAutoUpdater: SubscriptionsAutoUpdater
private let notifyWatchSubscriptionsResponseSubscriber: NotifyWatchSubscriptionsResponseSubscriber
private let notifyWatcherAgreementKeysProvider: NotifyWatcherAgreementKeysProvider
private let notifySubscriptionsChangedRequestSubscriber: NotifySubscriptionsChangedRequestSubscriber
private let notifySubscriptionsUpdater: NotifySubsctiptionsUpdater
private let subscriptionWatcher: SubscriptionWatcher

init(logger: ConsoleLogging,
Expand All @@ -47,17 +49,19 @@ public class NotifyClient {
pushClient: PushClient,
notifyMessageSubscriber: NotifyMessageSubscriber,
notifyStorage: NotifyStorage,
deleteNotifySubscriptionRequester: DeleteNotifySubscriptionRequester,
notifyDeleteSubscriptionRequester: NotifyDeleteSubscriptionRequester,
resubscribeService: NotifyResubscribeService,
notifySubscribeRequester: NotifySubscribeRequester,
notifySubscribeResponseSubscriber: NotifySubscribeResponseSubscriber,
notifyDeleteSubscriptionSubscriber: NotifyDeleteSubscriptionSubscriber,
notifyUpdateRequester: NotifyUpdateRequester,
notifyUpdateResponseSubscriber: NotifyUpdateResponseSubscriber,
notifyAccountProvider: NotifyAccountProvider,
subscriptionsAutoUpdater: SubscriptionsAutoUpdater,
notifyWatchSubscriptionsResponseSubscriber: NotifyWatchSubscriptionsResponseSubscriber,
notifyWatcherAgreementKeysProvider: NotifyWatcherAgreementKeysProvider,
notifySubscriptionsChangedRequestSubscriber: NotifySubscriptionsChangedRequestSubscriber,
notifySubscriptionsUpdater: NotifySubsctiptionsUpdater,
subscriptionWatcher: SubscriptionWatcher
) {
self.logger = logger
Expand All @@ -67,17 +71,19 @@ public class NotifyClient {
self.historyService = historyService
self.notifyMessageSubscriber = notifyMessageSubscriber
self.notifyStorage = notifyStorage
self.deleteNotifySubscriptionRequester = deleteNotifySubscriptionRequester
self.notifyDeleteSubscriptionRequester = notifyDeleteSubscriptionRequester
self.resubscribeService = resubscribeService
self.notifySubscribeRequester = notifySubscribeRequester
self.notifySubscribeResponseSubscriber = notifySubscribeResponseSubscriber
self.notifyDeleteSubscriptionSubscriber = notifyDeleteSubscriptionSubscriber
self.notifyUpdateRequester = notifyUpdateRequester
self.notifyUpdateResponseSubscriber = notifyUpdateResponseSubscriber
self.notifyAccountProvider = notifyAccountProvider
self.subscriptionsAutoUpdater = subscriptionsAutoUpdater
self.notifyWatchSubscriptionsResponseSubscriber = notifyWatchSubscriptionsResponseSubscriber
self.notifyWatcherAgreementKeysProvider = notifyWatcherAgreementKeysProvider
self.notifySubscriptionsChangedRequestSubscriber = notifySubscriptionsChangedRequestSubscriber
self.notifySubscriptionsUpdater = notifySubscriptionsUpdater
self.subscriptionWatcher = subscriptionWatcher
}

Expand Down Expand Up @@ -125,7 +131,7 @@ public class NotifyClient {
}

public func deleteSubscription(topic: String) async throws {
try await deleteNotifySubscriptionRequester.delete(topic: topic)
try await notifyDeleteSubscriptionRequester.delete(topic: topic)
}

public func deleteNotifyMessage(id: String) {
Expand Down Expand Up @@ -184,7 +190,7 @@ private extension NotifyClient {
extension NotifyClient {

public var subscriptionChangedPublisher: AnyPublisher<[NotifySubscription], Never> {
return notifySubscriptionsChangedRequestSubscriber.subscriptionChangedPublisher
return notifySubscriptionsUpdater.subscriptionChangedPublisher
}

public func register(deviceToken: String) async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,32 @@ public struct NotifyClientFactory {
let identityClient = IdentityClientFactory.create(keyserver: keyserverURL, keychain: keychainStorage, logger: logger)
let notifyMessageSubscriber = NotifyMessageSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, notifyStorage: notifyStorage, crypto: crypto, logger: logger)
let webDidResolver = NotifyWebDidResolver()
let deleteNotifySubscriptionRequester = DeleteNotifySubscriptionRequester(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, kms: kms, logger: logger, notifyStorage: notifyStorage)
let notifyDeleteSubscriptionRequester = NotifyDeleteSubscriptionRequester(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, notifyStorage: notifyStorage)
let resubscribeService = NotifyResubscribeService(networkInteractor: networkInteractor, notifyStorage: notifyStorage, logger: logger)

let notifyConfigProvider = NotifyConfigProvider(projectId: projectId, explorerHost: explorerHost)

let notifySubscribeRequester = NotifySubscribeRequester(keyserverURL: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, kms: kms, webDidResolver: webDidResolver, notifyConfigProvider: notifyConfigProvider)

let notifySubscribeResponseSubscriber = NotifySubscribeResponseSubscriber(networkingInteractor: networkInteractor, kms: kms, logger: logger, groupKeychainStorage: groupKeychainStorage, notifyStorage: notifyStorage, notifyConfigProvider: notifyConfigProvider)
let notifySubscriptionsUpdater = NotifySubsctiptionsUpdater(networkingInteractor: networkInteractor, kms: kms, logger: logger, notifyStorage: notifyStorage, groupKeychainStorage: groupKeychainStorage)

let notifySubscriptionsBuilder = NotifySubscriptionsBuilder(notifyConfigProvider: notifyConfigProvider)

let notifySubscribeResponseSubscriber = NotifySubscribeResponseSubscriber(networkingInteractor: networkInteractor, logger: logger, notifySubscriptionsBuilder: notifySubscriptionsBuilder, notifySubscriptionsUpdater: notifySubscriptionsUpdater)

let notifyUpdateRequester = NotifyUpdateRequester(keyserverURL: keyserverURL, identityClient: identityClient, networkingInteractor: networkInteractor, notifyConfigProvider: notifyConfigProvider, logger: logger, notifyStorage: notifyStorage)

let notifyUpdateResponseSubscriber = NotifyUpdateResponseSubscriber(networkingInteractor: networkInteractor, logger: logger, notifyConfigProvider: notifyConfigProvider, notifyStorage: notifyStorage)
let notifyUpdateResponseSubscriber = NotifyUpdateResponseSubscriber(networkingInteractor: networkInteractor, logger: logger, notifySubscriptionsBuilder: notifySubscriptionsBuilder, notifySubscriptionsUpdater: notifySubscriptionsUpdater)

let subscriptionsAutoUpdater = SubscriptionsAutoUpdater(notifyUpdateRequester: notifyUpdateRequester, logger: logger, notifyStorage: notifyStorage)

let notifyWatcherAgreementKeysProvider = NotifyWatcherAgreementKeysProvider(kms: kms)
let notifyWatchSubscriptionsRequester = NotifyWatchSubscriptionsRequester(keyserverURL: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, webDidResolver: webDidResolver, notifyAccountProvider: notifyAccountProvider, notifyWatcherAgreementKeysProvider: notifyWatcherAgreementKeysProvider, notifyHost: notifyHost)
let notifySubscriptionsBuilder = NotifySubscriptionsBuilder(notifyConfigProvider: notifyConfigProvider)
let notifyWatchSubscriptionsResponseSubscriber = NotifyWatchSubscriptionsResponseSubscriber(networkingInteractor: networkInteractor, kms: kms, logger: logger, notifyStorage: notifyStorage, groupKeychainStorage: groupKeychainStorage, notifySubscriptionsBuilder: notifySubscriptionsBuilder)
let notifySubscriptionsChangedRequestSubscriber = NotifySubscriptionsChangedRequestSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, kms: kms, identityClient: identityClient, logger: logger, groupKeychainStorage: groupKeychainStorage, notifyStorage: notifyStorage, notifySubscriptionsBuilder: notifySubscriptionsBuilder)
let notifyWatchSubscriptionsResponseSubscriber = NotifyWatchSubscriptionsResponseSubscriber(networkingInteractor: networkInteractor, logger: logger, notifySubscriptionsBuilder: notifySubscriptionsBuilder, notifySubscriptionsUpdater: notifySubscriptionsUpdater)
let notifySubscriptionsChangedRequestSubscriber = NotifySubscriptionsChangedRequestSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, logger: logger, notifySubscriptionsUpdater: notifySubscriptionsUpdater, notifySubscriptionsBuilder: notifySubscriptionsBuilder)
let subscriptionWatcher = SubscriptionWatcher(notifyWatchSubscriptionsRequester: notifyWatchSubscriptionsRequester, logger: logger)
let historyService = HistoryService(keyserver: keyserverURL, networkingClient: networkInteractor, identityClient: identityClient)
let notifyDeleteSubscriptionSubscriber = NotifyDeleteSubscriptionSubscriber(networkingInteractor: networkInteractor, kms: kms, logger: logger, notifySubscriptionsBuilder: notifySubscriptionsBuilder, notifySubscriptionsUpdater: notifySubscriptionsUpdater)

return NotifyClient(
logger: logger,
Expand All @@ -77,17 +81,19 @@ public struct NotifyClientFactory {
pushClient: pushClient,
notifyMessageSubscriber: notifyMessageSubscriber,
notifyStorage: notifyStorage,
deleteNotifySubscriptionRequester: deleteNotifySubscriptionRequester,
notifyDeleteSubscriptionRequester: notifyDeleteSubscriptionRequester,
resubscribeService: resubscribeService,
notifySubscribeRequester: notifySubscribeRequester,
notifySubscribeResponseSubscriber: notifySubscribeResponseSubscriber,
notifySubscribeResponseSubscriber: notifySubscribeResponseSubscriber,
notifyDeleteSubscriptionSubscriber: notifyDeleteSubscriptionSubscriber,
notifyUpdateRequester: notifyUpdateRequester,
notifyUpdateResponseSubscriber: notifyUpdateResponseSubscriber,
notifyAccountProvider: notifyAccountProvider,
subscriptionsAutoUpdater: subscriptionsAutoUpdater,
notifyWatchSubscriptionsResponseSubscriber: notifyWatchSubscriptionsResponseSubscriber,
notifyWatcherAgreementKeysProvider: notifyWatcherAgreementKeysProvider,
notifySubscriptionsChangedRequestSubscriber: notifySubscriptionsChangedRequestSubscriber,
notifySubscriptionsChangedRequestSubscriber: notifySubscriptionsChangedRequestSubscriber,
notifySubscriptionsUpdater: notifySubscriptionsUpdater,
subscriptionWatcher: subscriptionWatcher
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Foundation
import Combine

final class NotifySubsctiptionsUpdater {
private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementServiceProtocol
private let logger: ConsoleLogging
private let notifyStorage: NotifyStorage
private let groupKeychainStorage: KeychainStorageProtocol

private let subscriptionChangedSubject = PassthroughSubject<[NotifySubscription], Never>()

var subscriptionChangedPublisher: AnyPublisher<[NotifySubscription], Never> {
return subscriptionChangedSubject.eraseToAnyPublisher()
}

init(networkingInteractor: NetworkInteracting, kms: KeyManagementServiceProtocol, logger: ConsoleLogging, notifyStorage: NotifyStorage, groupKeychainStorage: KeychainStorageProtocol) {
self.networkingInteractor = networkingInteractor
self.kms = kms
self.logger = logger
self.notifyStorage = notifyStorage
self.groupKeychainStorage = groupKeychainStorage
}

func update(subscriptions newSubscriptions: [NotifySubscription], for account: Account) async throws {
let oldSubscriptions = notifyStorage.getSubscriptions(account: account)

subscriptionChangedSubject.send(newSubscriptions)

try Task.checkCancellation()

let subscriptions = oldSubscriptions.difference(from: newSubscriptions)

logger.debug("Received: \(newSubscriptions.count), changed: \(subscriptions.count)")

if subscriptions.count > 0 {
try notifyStorage.replaceAllSubscriptions(newSubscriptions)

for subscription in newSubscriptions {
let symKey = try SymmetricKey(hex: subscription.symKey)
try groupKeychainStorage.add(symKey, forKey: subscription.topic)
try kms.setSymmetricKey(symKey, for: subscription.topic)
}

let topicsToSubscribe = newSubscriptions.map { $0.topic }

let oldTopics = Set(oldSubscriptions.map { $0.topic })
let topicsToUnsubscribe = Array(oldTopics.subtracting(topicsToSubscribe))

try await networkingInteractor.batchUnsubscribe(topics: topicsToUnsubscribe)
try await networkingInteractor.batchSubscribe(topics: topicsToSubscribe)

try Task.checkCancellation()

logger.debug("Updated Subscriptions by Subscriptions Changed Request", properties: [
"topics": newSubscriptions.map { $0.topic }.joined(separator: ",")
])
}
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import Foundation

class DeleteNotifySubscriptionRequester {
class NotifyDeleteSubscriptionRequester {
enum Errors: Error {
case notifySubscriptionNotFound
}
private let keyserver: URL
private let networkingInteractor: NetworkInteracting
private let identityClient: IdentityClient
private let kms: KeyManagementServiceProtocol
private let logger: ConsoleLogging
private let notifyStorage: NotifyStorage

init(
keyserver: URL,
networkingInteractor: NetworkInteracting,
identityClient: IdentityClient,
kms: KeyManagementServiceProtocol,
logger: ConsoleLogging,
notifyStorage: NotifyStorage
) {
self.keyserver = keyserver
self.networkingInteractor = networkingInteractor
self.identityClient = identityClient
self.kms = kms
self.logger = logger
self.notifyStorage = notifyStorage
}
Expand All @@ -49,15 +46,11 @@ class DeleteNotifySubscriptionRequester {
try notifyStorage.deleteSubscription(topic: topic)
try notifyStorage.deleteMessages(topic: topic)

networkingInteractor.unsubscribe(topic: topic)
flypaper0 marked this conversation as resolved.
Show resolved Hide resolved

logger.debug("Subscription removed, topic: \(topic)")

kms.deleteSymmetricKey(for: topic)
logger.debug("Subscription delete request sent, topic: \(topic)")
}
}

private extension DeleteNotifySubscriptionRequester {
private extension NotifyDeleteSubscriptionRequester {

func createJWTWrapper(dappPubKey: DIDKey, reason: String, app: DIDWeb, account: Account) throws -> NotifyDeletePayload.Wrapper {
let jwtPayload = NotifyDeletePayload(account: account, keyserver: keyserver, dappPubKey: dappPubKey, app: app)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation
import Combine

class NotifyDeleteSubscriptionSubscriber {

private let networkingInteractor: NetworkInteracting
private let kms: KeyManagementServiceProtocol
private let logger: ConsoleLogging
private let notifySubscriptionsBuilder: NotifySubscriptionsBuilder
private let notifySubscriptionsUpdater: NotifySubsctiptionsUpdater

init(
networkingInteractor: NetworkInteracting,
kms: KeyManagementServiceProtocol,
logger: ConsoleLogging,
notifySubscriptionsBuilder: NotifySubscriptionsBuilder,
notifySubscriptionsUpdater: NotifySubsctiptionsUpdater
) {
self.networkingInteractor = networkingInteractor
self.kms = kms
self.logger = logger
self.notifySubscriptionsBuilder = notifySubscriptionsBuilder
self.notifySubscriptionsUpdater = notifySubscriptionsUpdater

subscribeForDeleteResponse()
}
}

private extension NotifyDeleteSubscriptionSubscriber {

func subscribeForDeleteResponse() {
networkingInteractor.subscribeOnResponse(
protocolMethod: NotifyDeleteProtocolMethod(),
requestOfType: NotifyDeletePayload.Wrapper.self,
responseOfType: NotifyDeleteResponsePayload.Wrapper.self,
errorHandler: logger
) { [unowned self] payload in

let (responsePayload, _) = try NotifyDeleteResponsePayload.decodeAndVerify(from: payload.response)

let subscriptions = try await notifySubscriptionsBuilder.buildSubscriptions(responsePayload.subscriptions)

try await notifySubscriptionsUpdater.update(subscriptions: subscriptions, for: responsePayload.account)

logger.debug("Received Notify Delete response")

networkingInteractor.unsubscribe(topic: payload.topic)
kms.deleteSymmetricKey(for: payload.topic)
}
}
}
Loading
Loading