a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
76 lines
2.5 KiB
Swift
76 lines
2.5 KiB
Swift
import Foundation
|
|
|
|
/// Describes a jcode server gateway endpoint.
|
|
///
|
|
/// The server exposes:
|
|
/// - `GET http://host:port/health` reachability + version probe
|
|
/// - `POST http://host:port/pair` pairing-code -> auth-token exchange
|
|
/// - `ws://host:port/ws` newline-delimited JSON protocol over WebSocket
|
|
public struct Gateway: Hashable, Sendable {
|
|
public static let defaultPort: UInt16 = 7643
|
|
|
|
public var host: String
|
|
public var port: UInt16
|
|
|
|
public init(host: String, port: UInt16 = Gateway.defaultPort) {
|
|
self.host = host
|
|
self.port = port
|
|
}
|
|
|
|
public var healthURL: URL {
|
|
url(scheme: "http", path: "/health")
|
|
}
|
|
|
|
public var pairURL: URL {
|
|
url(scheme: "http", path: "/pair")
|
|
}
|
|
|
|
public var webSocketURL: URL {
|
|
url(scheme: "ws", path: "/ws")
|
|
}
|
|
|
|
private func url(scheme: String, path: String) -> URL {
|
|
var components = URLComponents()
|
|
components.scheme = scheme
|
|
components.host = host
|
|
components.port = Int(port)
|
|
components.path = path
|
|
guard let url = components.url else {
|
|
// Host strings from pairing are validated before reaching here;
|
|
// a failure indicates programmer error.
|
|
preconditionFailure("invalid gateway endpoint: \(scheme)://\(host):\(port)\(path)")
|
|
}
|
|
return url
|
|
}
|
|
}
|
|
|
|
/// Parses `jcode://pair?host=H&port=P&code=C` URIs from QR codes.
|
|
public enum PairURI {
|
|
public struct Payload: Equatable, Sendable {
|
|
public var gateway: Gateway
|
|
public var code: String
|
|
|
|
public init(gateway: Gateway, code: String) {
|
|
self.gateway = gateway
|
|
self.code = code
|
|
}
|
|
}
|
|
|
|
public static func parse(_ string: String) -> Payload? {
|
|
guard let components = URLComponents(string: string),
|
|
components.scheme == "jcode",
|
|
components.host == "pair" || components.path == "pair"
|
|
|| components.host == nil && components.path == "/pair"
|
|
else { return nil }
|
|
let items = components.queryItems ?? []
|
|
func value(_ name: String) -> String? {
|
|
items.first(where: { $0.name == name })?.value
|
|
}
|
|
guard let host = value("host"), !host.isEmpty,
|
|
let code = value("code"), !code.isEmpty
|
|
else { return nil }
|
|
let port = value("port").flatMap(UInt16.init) ?? Gateway.defaultPort
|
|
return Payload(gateway: Gateway(host: host, port: port), code: code)
|
|
}
|
|
}
|