Created
January 19, 2020 22:35
-
-
Save ryanashcraft/bca678bf61ac427675b730cd0054806f to your computer and use it in GitHub Desktop.
RemoteInspector.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public class RemoteInspector { | |
private struct UpdateMessage<T: Encodable>: Encodable { | |
let type = "update" | |
var id: String | |
var data: T | |
} | |
private struct LogMessage: Encodable { | |
let type = "log" | |
var message: String | |
var level: String | |
var attributesJSON: String? | |
} | |
public static let shared = RemoteInspector() | |
static func connect(url: URL) -> URLSessionWebSocketTask { | |
let urlSession = URLSession(configuration: .default) | |
return urlSession.webSocketTask(with: url) | |
} | |
var webSocketTask: URLSessionWebSocketTask? | |
var url: URL? | |
public var isConnected: Bool { | |
return webSocketTask?.state == .running | |
} | |
public func connect(url: URL) -> Bool { | |
#if !DEBUG | |
return false | |
#else | |
self.url = url | |
webSocketTask = Self.connect(url: url) | |
if let webSocketTask = webSocketTask { | |
logger.infoMessage("Starting remote inspector session at \(url.absoluteString)") | |
webSocketTask.resume() | |
return true | |
} | |
return false | |
#endif | |
} | |
func reconnect() -> Bool { | |
guard let webSocketTask = webSocketTask else { | |
return false | |
} | |
webSocketTask.cancel(with: .goingAway, reason: nil) | |
if let url = url { | |
return connect(url: url) | |
} | |
return false | |
} | |
public func disconnect() { | |
guard let webSocketTask = webSocketTask else { | |
return | |
} | |
webSocketTask.cancel(with: .goingAway, reason: nil) | |
self.webSocketTask = nil | |
} | |
public func send(_ id: String, _ value: Encodable) { | |
guard let webSocketTask = webSocketTask else { | |
return | |
} | |
do { | |
let encoder = JSONEncoder() | |
let jsonData = try encoder.encode(UpdateMessage(id: id, data: AnyEncodable(value: value))) | |
let message = URLSessionWebSocketTask.Message.data(jsonData) | |
webSocketTask.send(message) { error in | |
if let error = error { | |
_ = self.reconnect() | |
logger.errorMessage("\(error)") | |
} | |
} | |
} catch { | |
// Blegh | |
} | |
} | |
func log(_ message: String, logLevel: String, attributes: [String: Any]? = nil) { | |
guard let webSocketTask = webSocketTask else { | |
return | |
} | |
let encoder = JSONEncoder() | |
var attributesJSON: Data? | |
if let attributes = attributes { | |
attributesJSON = try? JSONSerialization.data(withJSONObject: attributes, options: []) | |
} | |
guard let jsonData: Data = { | |
do { | |
if let attributesJSON = attributesJSON { | |
return try encoder.encode( | |
LogMessage( | |
message: message, | |
level: logLevel.description, | |
attributesJSON: String(data: attributesJSON, encoding: .utf8) | |
) | |
) | |
} else { | |
return try encoder.encode( | |
LogMessage( | |
message: message, | |
level: logLevel.description, | |
attributesJSON: nil | |
) | |
) | |
} | |
} catch { | |
return nil | |
} | |
}() else { | |
return | |
} | |
let message = URLSessionWebSocketTask.Message.data(jsonData) | |
webSocketTask.send(message) { error in | |
if let error = error { | |
_ = self.reconnect() | |
logger.errorMessage("\(error)") | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment