Skip to content

Commit

Permalink
Merge pull request #1223 from WalletConnect/develop
Browse files Browse the repository at this point in the history
1.9.7
  • Loading branch information
flypaper0 authored Nov 9, 2023
2 parents 4aa4c82 + 3aa5c58 commit c1e8075
Show file tree
Hide file tree
Showing 17 changed files with 194 additions and 123 deletions.
131 changes: 72 additions & 59 deletions Example/IntegrationTests/Push/NotifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class NotifyTests: XCTestCase {

let gmDappDomain = InputConfig.gmDappHost

let pk = try! EthereumPrivateKey()
var pk: EthereumPrivateKey!

var privateKey: Data {
return Data(pk.rawPrivateKey)
Expand Down Expand Up @@ -93,111 +93,122 @@ final class NotifyTests: XCTestCase {
}

override func setUp() {
pk = try! EthereumPrivateKey()
walletNotifyClientA = makeWalletClient()
}

func testWalletCreatesSubscription() async {
func testWalletCreatesSubscription() async throws {
let expectation = expectation(description: "expects to create notify subscription")
expectation.assertForOverFulfill = false

var subscription: NotifySubscription?

walletNotifyClientA.subscriptionsPublisher
.sink { [unowned self] subscriptions in
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
try await walletNotifyClientA.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
.sink { subscriptions in
subscription = subscriptions.first
expectation.fulfill()
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)
try await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout)

if let subscription {
try await walletNotifyClientA.deleteSubscription(topic: subscription.topic)
}
}

func testNotifyWatchSubscriptions() async throws {
let expectation = expectation(description: "expects client B to receive subscription created by client A")
expectation.assertForOverFulfill = false

var subscription: NotifySubscription?

let clientB = makeWalletClient(prefix: "👐🏼 Wallet B: ")
clientB.subscriptionsPublisher.sink { subscriptions in
guard let subscription = subscriptions.first else { return }
Task(priority: .high) {
try await clientB.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
subscription = subscriptions.first
expectation.fulfill()
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)
try! await clientB.register(account: account, domain: gmDappDomain, onSign: sign)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout)

if let subscription {
try await clientB.deleteSubscription(topic: subscription.topic)
}
}

func testNotifySubscriptionChanged() async throws {
let expectation = expectation(description: "expects client B to receive subscription after both clients are registered and client A creates one")
expectation.assertForOverFulfill = false

var subscription: NotifySubscription!
var subscription: NotifySubscription?

let clientB = makeWalletClient(prefix: "👐🏼 Wallet B: ")
clientB.subscriptionsPublisher.sink { subscriptions in
guard let newSubscription = subscriptions.first else { return }
subscription = newSubscription
subscription = subscriptions.first
expectation.fulfill()
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await clientB.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout)

try await clientB.deleteSubscription(topic: subscription.topic)
if let subscription {
try await clientB.deleteSubscription(topic: subscription.topic)
}
}

func testWalletCreatesAndUpdatesSubscription() async {
let expectation = expectation(description: "expects to create and update notify subscription")
expectation.assertForOverFulfill = false
func testWalletCreatesAndUpdatesSubscription() async throws {
let created = expectation(description: "Subscription created")

var updateScope: Set<String>!
var didUpdate = false

walletNotifyClientA.subscriptionsPublisher
.sink { [unowned self] subscriptions in
guard
let subscription = subscriptions.first,
let scope = subscription.scope.keys.first
else { return }
let updated = expectation(description: "Subscription Updated")

let updatedScope = Set(subscription.scope.filter { $0.value.enabled == true }.keys)
var isCreated = false
var isUpdated = false
var subscription: NotifySubscription!

if !didUpdate {
updateScope = Set([scope])
didUpdate = true
Task(priority: .high) {
try await walletNotifyClientA.update(topic: subscription.topic, scope: Set([scope]))
}
}
if updateScope == updatedScope {
Task(priority: .high) {
try await walletNotifyClientA.deleteSubscription(topic: subscription.topic)
expectation.fulfill()
}
walletNotifyClientA.subscriptionsPublisher
.sink { subscriptions in
subscription = subscriptions.first

if !isCreated {
isCreated = true
created.fulfill()
} else if !isUpdated {
isUpdated = true
updated.fulfill()
}
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)
try await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

await fulfillment(of: [created], timeout: InputConfig.defaultTimeout)

let updateScope = Set([subscription.scope.keys.first!])
try await walletNotifyClientA.update(topic: subscription.topic, scope: updateScope)

await fulfillment(of: [updated], timeout: InputConfig.defaultTimeout)

wait(for: [expectation], timeout: InputConfig.defaultTimeout)
let updatedScope = Set(subscription.scope.filter { $0.value.enabled == true }.keys)
XCTAssertEqual(updatedScope, updateScope)

try await walletNotifyClientA.deleteSubscription(topic: subscription.topic)
}

func testNotifyServerSubscribeAndNotifies() async throws {
let subscribeExpectation = expectation(description: "creates notify subscription")
let messageExpectation = expectation(description: "receives a notify message")

var notifyMessage: NotifyMessage!
var notifyMessageRecord: NotifyMessageRecord?

var didNotify = false
walletNotifyClientA.subscriptionsPublisher
Expand All @@ -221,20 +232,22 @@ final class NotifyTests: XCTestCase {
}
}.store(in: &publishers)

walletNotifyClientA.notifyMessagePublisher
.sink { [unowned self] notifyMessageRecord in
XCTAssertEqual(notifyMessageRecord.message, notifyMessage)

Task(priority: .high) {
try await walletNotifyClientA.deleteSubscription(topic: notifyMessageRecord.topic)
messageExpectation.fulfill()
}
walletNotifyClientA.messagesPublisher
.sink { messages in
guard let newNotifyMessageRecord = messages.first else { return }
XCTAssertEqual(newNotifyMessageRecord.message, notifyMessage)
notifyMessageRecord = newNotifyMessageRecord
messageExpectation.fulfill()
}.store(in: &publishers)

try! await walletNotifyClientA.register(account: account, domain: gmDappDomain, onSign: sign)
try! await walletNotifyClientA.subscribe(appDomain: gmDappDomain, account: account)

wait(for: [subscribeExpectation, messageExpectation], timeout: InputConfig.defaultTimeout)
await fulfillment(of: [subscribeExpectation, messageExpectation], timeout: InputConfig.defaultTimeout)

if let notifyMessageRecord {
try await walletNotifyClientA.deleteSubscription(topic: notifyMessageRecord.topic)
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Combine
final class NotificationsInteractor {

var subscriptionsPublisher: AnyPublisher<[NotifySubscription], Never> {
return Notify.instance.subscriptionsPublisher
return Notify.instance.subscriptionsPublisher(account: importAccount.account)
}

private let importAccount: ImportAccount
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ let package = Package(
dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]),
.target(
name: "Database",
dependencies: []),
dependencies: ["WalletConnectUtils"]),
.target(
name: "WalletConnectModal",
dependencies: ["QRCode", "WalletConnectSign"],
Expand Down
3 changes: 3 additions & 0 deletions Sources/Database/DatabaseImports.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#if !CocoaPods
@_exported import WalletConnectUtils
#endif
46 changes: 28 additions & 18 deletions Sources/Database/DiskSqlite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,50 @@ public final class DiskSqlite: Sqlite {

private var db: OpaquePointer?

private let lock = UnfairLock()

public init(path: String) {
self.path = path
}

public func openDatabase() throws {
guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
throw SQLiteError.openDatabase(path: path)
try lock.locked {
guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
throw SQLiteError.openDatabase(path: path)
}
}
}

public func query<Row: SqliteRow>(sql: String) throws -> [Row] {
var queryStatement: OpaquePointer?
guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
throw SQLiteError.queryPrepare(statement: sql)
}
var rows: [Row] = []
while sqlite3_step(queryStatement) == SQLITE_ROW {
let decoder = SqliteRowDecoder(statement: queryStatement)
guard let row = try? Row(decoder: decoder) else { continue }
rows.append(row)
return try lock.locked {
var queryStatement: OpaquePointer?
guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
throw SQLiteError.queryPrepare(statement: sql)
}
var rows: [Row] = []
while sqlite3_step(queryStatement) == SQLITE_ROW {
let decoder = SqliteRowDecoder(statement: queryStatement)
guard let row = try? Row(decoder: decoder) else { continue }
rows.append(row)
}
sqlite3_finalize(queryStatement)
return rows
}
sqlite3_finalize(queryStatement)
return rows
}

public func execute(sql: String) throws {
var error: UnsafeMutablePointer<CChar>?
guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
let message = error.map { String(cString: $0) }
throw SQLiteError.exec(error: message)
try lock.locked {
var error: UnsafeMutablePointer<CChar>?
guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
let message = error.map { String(cString: $0) }
throw SQLiteError.exec(error: message)
}
}
}

public func closeConnection() {
sqlite3_close(db)
lock.locked {
sqlite3_close(db)
}
}
}
22 changes: 21 additions & 1 deletion Sources/WalletConnectModal/Extensions/View+Backport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftUI

extension View {

#if os(iOS)
#if os(iOS) || os(tvOS)

/// A backwards compatible wrapper for iOS 14 `onChange`
@ViewBuilder
Expand All @@ -27,4 +27,24 @@ extension View {
}

#endif

#if os(iOS) || os(macOS)

@ViewBuilder
func onTapGestureBackported(count: Int = 1, perform action: @escaping () -> Void) -> some View {
self
}

#elseif os(tvOS)

@ViewBuilder
func onTapGestureBackported(count: Int = 1, perform action: @escaping () -> Void) -> some View {
if #available(tvOS 16.0, *) {
self.onTapGesture(count: count, perform: action)
} else {
self
}
}

#endif
}
12 changes: 4 additions & 8 deletions Sources/WalletConnectModal/Modal/ModalContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@ struct ModalContainerView: View {
Color.thickOverlay
.colorScheme(.light)
.opacity(showModal ? 1 : 0)
.transform {
#if os(iOS)
$0.onTapGesture {
withAnimation {
showModal = false
}
}
#endif
.onTapGestureBackported {
withAnimation {
showModal = false
}
}
)
.edgesIgnoringSafeArea(.all)
Expand Down
10 changes: 7 additions & 3 deletions Sources/WalletConnectModal/Modal/Screens/QRCodeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,13 @@ struct QRCodeView: View {
)
)

return doc.imageUI(
size, label: Text("QR code with URI")
)!
if #available(macOS 11, *) {
return doc.imageUI(
size, label: Text("QR code with URI")
)!
} else {
return Image.init(sfSymbolName: "qrcode")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct WalletDetail: View {
.contentShape(Rectangle())
.padding(.horizontal, 8)
.padding(.vertical, 8)
.onTapGesture {
.onTapGestureBackported {
withAnimation(.easeInOut(duration: 0.15)) {
viewModel.preferredPlatform = item
}
Expand Down Expand Up @@ -185,7 +185,7 @@ struct WalletDetail: View {
.foregroundColor(.foreground2)
}
}
.onTapGesture {
.onTapGestureBackported {
viewModel.handle(.didTapAppStore)
}
}
Expand Down
Loading

0 comments on commit c1e8075

Please sign in to comment.