Skip to content

Commit

Permalink
Merge pull request #944 from WalletConnect/subscription-auto-update
Browse files Browse the repository at this point in the history
[Push] Subscriptions auto update
  • Loading branch information
llbartekll authored Jul 6, 2023
2 parents e56f00a + de21e62 commit 8d8b97d
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@
ReferencedContainer = "container:..">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NotifyTests"
BuildableName = "NotifyTests"
BlueprintName = "NotifyTests"
ReferencedContainer = "container:..">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand All @@ -28,6 +42,16 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NotifyTests"
BuildableName = "NotifyTests"
BlueprintName = "NotifyTests"
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ let package = Package(
.testTarget(
name: "ChatTests",
dependencies: ["WalletConnectChat", "WalletConnectUtils", "TestingUtils"]),
.testTarget(
name: "NotifyTests",
dependencies: ["WalletConnectPush", "TestingUtils"]),
.testTarget(
name: "AuthTests",
dependencies: ["Auth", "WalletConnectUtils", "TestingUtils", "WalletConnectVerify"]),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Foundation

class NotifyUpdateRequester {
protocol NotifyUpdateRequesting {
func update(topic: String, scope: Set<String>) async throws
}

class NotifyUpdateRequester: NotifyUpdateRequesting {
enum Errors: Error {
case noSubscriptionForGivenTopic
}
Expand Down
9 changes: 8 additions & 1 deletion Sources/WalletConnectPush/Client/Wallet/PushStorage.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import Foundation
import Combine

final class PushStorage {
protocol PushStoring {
func getSubscriptions() -> [PushSubscription]
func getSubscription(topic: String) -> PushSubscription?
func setSubscription(_ subscription: PushSubscription) async throws
func deleteSubscription(topic: String) async throws
}

final class PushStorage: PushStoring {

private var publishers = Set<AnyCancellable>()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

import Foundation

class SubscriptionsAutoUpdater {
private let notifyUpdateRequester: NotifyUpdateRequesting
private let logger: ConsoleLogging
private let pushStorage: PushStoring

init(notifyUpdateRequester: NotifyUpdateRequesting,
logger: ConsoleLogging,
pushStorage: PushStoring) {
self.notifyUpdateRequester = notifyUpdateRequester
self.logger = logger
self.pushStorage = pushStorage
updateSubscriptionsIfNeeded()
}

private func updateSubscriptionsIfNeeded() {
for subscription in pushStorage.getSubscriptions() {
if shouldUpdate(subscription: subscription) {
let scope = Set(subscription.scope.filter{ $0.value.enabled == true }.keys)
let topic = subscription.topic
Task {
do {
try await notifyUpdateRequester.update(topic: topic, scope: scope)
} catch {
logger.error("Failed to update subscription for topic: \(topic)")
}
}
}
}
}

private func shouldUpdate(subscription: PushSubscription) -> Bool {
let currentDate = Date()
let calendar = Calendar.current
let expiryDate = subscription.expiry
let dateComponents = calendar.dateComponents([.day], from: currentDate, to: expiryDate)
if let numberOfDays = dateComponents.day,
numberOfDays < 14 {
return true
} else {
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class WalletPushClient {
private let notifyUpdateResponseSubscriber: NotifyUpdateResponseSubscriber
private let notifyProposeResponder: NotifyProposeResponder
private let notifyProposeSubscriber: NotifyProposeSubscriber
private let subscriptionsAutoUpdater: SubscriptionsAutoUpdater

init(logger: ConsoleLogging,
kms: KeyManagementServiceProtocol,
Expand All @@ -68,7 +69,8 @@ public class WalletPushClient {
notifyUpdateRequester: NotifyUpdateRequester,
notifyUpdateResponseSubscriber: NotifyUpdateResponseSubscriber,
notifyProposeResponder: NotifyProposeResponder,
notifyProposeSubscriber: NotifyProposeSubscriber
notifyProposeSubscriber: NotifyProposeSubscriber,
subscriptionsAutoUpdater: SubscriptionsAutoUpdater
) {
self.logger = logger
self.echoClient = echoClient
Expand All @@ -85,6 +87,7 @@ public class WalletPushClient {
self.notifyUpdateResponseSubscriber = notifyUpdateResponseSubscriber
self.notifyProposeResponder = notifyProposeResponder
self.notifyProposeSubscriber = notifyProposeSubscriber
self.subscriptionsAutoUpdater = subscriptionsAutoUpdater
}

public func enableSync(account: Account, onSign: @escaping SigningCallback) async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public struct WalletPushClientFactory {

let deletePushSubscriptionSubscriber = DeletePushSubscriptionSubscriber(networkingInteractor: networkInteractor, kms: kms, logger: logger, pushStorage: pushStorage)

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

return WalletPushClient(
logger: logger,
kms: kms,
Expand All @@ -78,7 +80,8 @@ public struct WalletPushClientFactory {
notifyUpdateRequester: notifyUpdateRequester,
notifyUpdateResponseSubscriber: notifyUpdateResponseSubscriber,
notifyProposeResponder: notifyProposeResponder,
notifyProposeSubscriber: notifyProposeSubscriber
notifyProposeSubscriber: notifyProposeSubscriber,
subscriptionsAutoUpdater: subscriptionsAutoUpdater
)
}
}
15 changes: 15 additions & 0 deletions Tests/NotifyTests/Mocks/MockNotifyUpdateRequester.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

import Foundation
@testable import WalletConnectPush


class MockNotifyUpdateRequester: NotifyUpdateRequesting {
var updatedTopics: [String] = []
var completionHandler: (() -> Void)?

func update(topic: String, scope: Set<String>) async throws {
updatedTopics.append(topic)
completionHandler?()
}
}

31 changes: 31 additions & 0 deletions Tests/NotifyTests/Mocks/MockPushStoring.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import Foundation
@testable import WalletConnectPush

class MockPushStoring: PushStoring {
var subscriptions: [PushSubscription]

init(subscriptions: [PushSubscription]) {
self.subscriptions = subscriptions
}

func getSubscriptions() -> [PushSubscription] {
return subscriptions
}

func getSubscription(topic: String) -> PushSubscription? {
return subscriptions.first { $0.topic == topic }
}

func setSubscription(_ subscription: PushSubscription) async throws {
if let index = subscriptions.firstIndex(where: { $0.topic == subscription.topic }) {
subscriptions[index] = subscription
} else {
subscriptions.append(subscription)
}
}

func deleteSubscription(topic: String) async throws {
subscriptions.removeAll(where: { $0.topic == topic })
}
}
23 changes: 23 additions & 0 deletions Tests/NotifyTests/Stubs/PushSubscription.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

import Foundation
@testable import WalletConnectPush

extension PushSubscription {
static func stub(topic: String, expiry: Date) -> PushSubscription {
let account = Account(chainIdentifier: "eip155:1", address: "0x15bca56b6e2728aec2532df9d436bd1600e86688")!
let relay = RelayProtocolOptions.stub()
let metadata = AppMetadata.stub()
let symKey = "key1"

return PushSubscription(
topic: topic,
account: account,
relay: relay,
metadata: metadata,
scope: ["test": ScopeValue(description: "desc", enabled: true)],
expiry: expiry,
symKey: symKey
)
}
}

36 changes: 36 additions & 0 deletions Tests/NotifyTests/SubscriptionsAutoUpdaterTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation
import XCTest
import TestingUtils
@testable import WalletConnectPush

class SubscriptionsAutoUpdaterTests: XCTestCase {
var sut: SubscriptionsAutoUpdater!

func testUpdateSubscriptionsIfNeeded() async {
let subscriptions: [PushSubscription] = [
PushSubscription.stub(topic: "topic1", expiry: Date().addingTimeInterval(60 * 60 * 24 * 20)),
PushSubscription.stub(topic: "topic2", expiry: Date().addingTimeInterval(60 * 60 * 24 * 10)),
PushSubscription.stub(topic: "topic3", expiry: Date().addingTimeInterval(60 * 60 * 24 * 30))
]

let expectation = expectation(description: "update")

let notifyUpdateRequester = MockNotifyUpdateRequester()
let logger = ConsoleLoggerMock()
let pushStorage = MockPushStoring(subscriptions: subscriptions)

notifyUpdateRequester.completionHandler = {
if notifyUpdateRequester.updatedTopics.contains("topic2") {
expectation.fulfill()
}
}

sut = SubscriptionsAutoUpdater(notifyUpdateRequester: notifyUpdateRequester,
logger: logger,
pushStorage: pushStorage)

await waitForExpectations(timeout: 1, handler: nil)

XCTAssertEqual(notifyUpdateRequester.updatedTopics, ["topic2"])
}
}

0 comments on commit 8d8b97d

Please sign in to comment.