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

#11 auto/manual socket connection #66

Merged
merged 22 commits into from
Feb 9, 2022
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
9 changes: 3 additions & 6 deletions Example/DApp/ClientDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import WalletConnect
import Relayer

class ClientDelegate: WalletConnectClientDelegate {
var client: WalletConnectClient
Expand All @@ -13,12 +14,8 @@ class ClientDelegate: WalletConnectClientDelegate {
description: "a description",
url: "wallet.connect",
icons: ["https://gblobscdn.gitbook.com/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png?alt=media"])
self.client = WalletConnectClient(
metadata: metadata,
projectId: "52af113ee0c1e1a20f4995730196c13e",
isController: false,
relayHost: "relay.dev.walletconnect.com"
)
let relayer = Relayer(relayHost: "relay.dev.walletconnect.com", projectId: "52af113ee0c1e1a20f4995730196c13e")
self.client = WalletConnectClient(metadata: metadata, isController: false, relayer: relayer)
client.delegate = self
}

Expand Down
2 changes: 1 addition & 1 deletion Example/DApp/Connect/ConnectViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ConnectViewController: UIViewController, UITableViewDataSource, UITableVie

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "pairing_cell", for: indexPath)
cell.textLabel?.text = activePairings[indexPath.row].peer!.name
cell.textLabel?.text = activePairings[indexPath.row].peer?.name ?? ""
return cell
}

Expand Down
48 changes: 48 additions & 0 deletions Sources/Relayer/AppStateObserving.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

import Foundation
#if os(iOS)
import UIKit
#endif

protocol AppStateObserving {
var onWillEnterForeground: (()->())? {get set}
var onWillEnterBackground: (()->())? {get set}
}

class AppStateObserver: AppStateObserving {
@objc var onWillEnterForeground: (() -> ())?

@objc var onWillEnterBackground: (() -> ())?

init() {
subscribeNotificationCenter()
}

private func subscribeNotificationCenter() {
#if os(iOS)
NotificationCenter.default.addObserver(
self,
selector: #selector(appWillEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(appWillEnterBackground),
name: UIApplication.willResignActiveNotification,
object: nil)
#endif
}

@objc
private func appWillEnterBackground() {
onWillEnterBackground?()
}

@objc
private func appWillEnterForeground() {
onWillEnterForeground?()
}

}


44 changes: 13 additions & 31 deletions Sources/Relayer/Dispatching.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,53 @@ protocol Dispatching {
var onDisconnect: (()->())? {get set}
var onMessage: ((String) -> ())? {get set}
func send(_ string: String, completion: @escaping (Error?)->())
func connect()
func disconnect(closeCode: URLSessionWebSocketTask.CloseCode)
func connect() throws
func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws
}

final class Dispatcher: NSObject, Dispatching {
var onConnect: (() -> ())?
var onDisconnect: (() -> ())?
var onMessage: ((String) -> ())?
private var textFramesQueue = Queue<String>()
private var networkMonitor: NetworkMonitoring
private let url: URL
var socket: WebSocketSessionProtocol
var socketConnectionObserver: SocketConnectionObserving
var socketConnectionHandler: SocketConnectionHandler

init(url: URL,
networkMonitor: NetworkMonitoring = NetworkMonitor(),
socket: WebSocketSessionProtocol,
socketConnectionObserver: SocketConnectionObserving) {
self.url = url
self.networkMonitor = networkMonitor
init(socket: WebSocketSessionProtocol,
socketConnectionObserver: SocketConnectionObserving,
socketConnectionHandler: SocketConnectionHandler) {
self.socket = socket
self.socketConnectionObserver = socketConnectionObserver
self.socketConnectionHandler = socketConnectionHandler
super.init()
setUpWebSocketSession()
setUpSocketConnectionObserving()
setUpNetworkMonitoring()
socket.connect(on: url)
}

func send(_ string: String, completion: @escaping (Error?) -> Void) {
if socket.isConnected {
self.socket.send(string, completionHandler: completion)
//TODO - enqueue if fails

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

} else {
textFramesQueue.enqueue(string)
}
}

func connect() {
if !socket.isConnected {
socket.connect(on: url)
}
func connect() throws {
try socketConnectionHandler.handleConnect()
}

func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) {
socket.disconnect(with: closeCode)
onDisconnect?()
func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws {
try socketConnectionHandler.handleDisconnect(closeCode: closeCode)
}

private func setUpWebSocketSession() {
socket.onMessageReceived = { [weak self] in
self?.onMessage?($0)
}
socket.onMessageError = { error in
print(error)
print("WebSocket Error \(error)")
}
}

Expand All @@ -73,16 +66,6 @@ final class Dispatcher: NSObject, Dispatching {
}
}

private func setUpNetworkMonitoring() {
networkMonitor.onSatisfied = { [weak self] in
self?.connect()
}
networkMonitor.onUnsatisfied = { [weak self] in
self?.disconnect(closeCode: .goingAway)
}
networkMonitor.startMonitoring()
}

private func dequeuePendingTextFrames() {
while let frame = textFramesQueue.dequeue() {
send(frame) { error in
Expand All @@ -93,4 +76,3 @@ final class Dispatcher: NSObject, Dispatching {
}
}
}

1 change: 1 addition & 0 deletions Sources/Relayer/NetworkMonitoring.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ class NetworkMonitor: NetworkMonitoring {
monitor.start(queue: monitorQueue)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Combine
import WalletConnectUtils


public final class WakuNetworkRelay {
public final class Relayer {
enum RelyerError: Error {
case subscriptionIdNotFound
}
Expand All @@ -28,7 +28,7 @@ public final class WakuNetworkRelay {
requestAcknowledgePublisherSubject.eraseToAnyPublisher()
}
private let requestAcknowledgePublisherSubject = PassthroughSubject<JSONRPCResponse<Bool>, Never>()
private let logger: ConsoleLogging
let logger: ConsoleLogging

init(dispatcher: Dispatching,
logger: ConsoleLogging,
Expand All @@ -41,26 +41,44 @@ public final class WakuNetworkRelay {
setUpBindings()
}

public convenience init(logger: ConsoleLogging,
url: URL,
keyValueStorage: KeyValueStorage,
uniqueIdentifier: String) {
/// Instantiates Relayer
/// - Parameters:
/// - relayHost: proxy server host that your application will use to connect to Waku Network. If you register your project at `www.walletconnect.com` you can use `relay.walletconnect.com`
/// - projectId: an optional parameter used to access the public WalletConnect infrastructure. Go to `www.walletconnect.com` for info.
/// - keyValueStorage: by default WalletConnect SDK will store sequences in UserDefaults
/// - uniqueIdentifier: if your app requires more than one relayer instances you are required to call identify them
/// - socketConnectionType: socket connection type
/// - logger: logger instance
public convenience init(relayHost: String,
projectId: String,
keyValueStorage: KeyValueStorage = UserDefaults.standard,
uniqueIdentifier: String? = nil,
socketConnectionType: SocketConnectionType = .automatic,
logger: ConsoleLogging = ConsoleLogger(loggingLevel: .off)) {
let socketConnectionObserver = SocketConnectionObserver()
let urlSession = URLSession(configuration: .default, delegate: socketConnectionObserver, delegateQueue: OperationQueue())
let socket = WebSocketSession(session: urlSession)
let dispatcher = Dispatcher(url: url, socket: socket, socketConnectionObserver: socketConnectionObserver)
let url = Self.makeRelayUrl(host: relayHost, projectId: projectId)
let socket = WebSocketSession(session: urlSession, url: url)
var socketConnectionHandler: SocketConnectionHandler
switch socketConnectionType {
case .automatic:
socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket)
case .manual:
socketConnectionHandler = ManualSocketConnectionHandler(socket: socket)
}
let dispatcher = Dispatcher(socket: socket, socketConnectionObserver: socketConnectionObserver, socketConnectionHandler: socketConnectionHandler)
self.init(dispatcher: dispatcher,
logger: logger,
keyValueStorage: keyValueStorage,
uniqueIdentifier: uniqueIdentifier)
uniqueIdentifier: uniqueIdentifier ?? "")
}

public func connect() {
dispatcher.connect()
public func connect() throws {
try dispatcher.connect()
}

public func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) {
dispatcher.disconnect(closeCode: closeCode)
public func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws {
try dispatcher.disconnect(closeCode: closeCode)
}

@discardableResult public func publish(topic: String, payload: String, completion: @escaping ((Error?) -> ())) -> Int64 {
Expand Down Expand Up @@ -192,7 +210,7 @@ public final class WakuNetworkRelay {
}
}

static public func makeRelayUrl(host: String, projectId: String) -> URL {
static private func makeRelayUrl(host: String, projectId: String) -> URL {
var components = URLComponents()
components.scheme = "wss"
components.host = host
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

#if os(iOS)
import UIKit
#endif
import Foundation

class AutomaticSocketConnectionHandler: SocketConnectionHandler {
enum Error: Swift.Error {
case manualSocketConnectionForbidden
case manualSocketDisconnectionForbidden
}
private var appStateObserver: AppStateObserving
let socket: WebSocketConnecting
private var networkMonitor: NetworkMonitoring
private let backgroundTaskRegistrar: BackgroundTaskRegistering

init(networkMonitor: NetworkMonitoring = NetworkMonitor(),
socket: WebSocketConnecting,
appStateObserver: AppStateObserving = AppStateObserver(),
backgroundTaskRegistrar: BackgroundTaskRegistering = BackgroundTaskRegistrar()) {
self.appStateObserver = appStateObserver
self.socket = socket
self.networkMonitor = networkMonitor
self.backgroundTaskRegistrar = backgroundTaskRegistrar
setUpStateObserving()
setUpNetworkMonitoring()
socket.connect()
}

private func setUpStateObserving() {
appStateObserver.onWillEnterBackground = { [unowned self] in
registerBackgroundTask()
}

appStateObserver.onWillEnterForeground = { [unowned self] in
socket.connect()
}
}

private func setUpNetworkMonitoring() {
networkMonitor.onSatisfied = { [weak self] in
self?.handleNetworkSatisfied()
}
networkMonitor.onUnsatisfied = { [weak self] in
self?.handleNetworkUnsatisfied()
}
networkMonitor.startMonitoring()
}

func registerBackgroundTask() {
backgroundTaskRegistrar.register(name: "Finish Network Tasks") { [unowned self] in
endBackgroundTask()
}
}

func endBackgroundTask() {
socket.disconnect(with: .normalClosure)
}

func handleConnect() throws {
throw Error.manualSocketConnectionForbidden
}

func handleDisconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws {
throw Error.manualSocketDisconnectionForbidden
}

func handleNetworkUnsatisfied() {
socket.disconnect(with: .goingAway)
}

func handleNetworkSatisfied() {
if !socket.isConnected {
socket.connect()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

import Foundation
#if os(iOS)
import UIKit
#endif

protocol BackgroundTaskRegistering {
func register(name: String, completion: @escaping ()->())
}

class BackgroundTaskRegistrar: BackgroundTaskRegistering {
#if os(iOS)
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
#endif

func register(name: String, completion: @escaping () -> ()) {
#if os(iOS)
backgroundTaskID = .invalid
backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: name) { [unowned self] in
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
completion()
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

import Foundation

class ManualSocketConnectionHandler: SocketConnectionHandler {
var socket: WebSocketConnecting

init(socket: WebSocketConnecting) {
self.socket = socket
}

func handleConnect() throws {
socket.connect()
}

func handleDisconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws {
socket.disconnect(with: closeCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

import Foundation

protocol SocketConnectionHandler {
var socket: WebSocketConnecting {get}
func handleConnect() throws
func handleDisconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws
}
Loading