remote(client): support connecting to specified host and port
This commit is contained in:
parent
38b5144cf8
commit
427a2012a4
|
@ -142,7 +142,11 @@ private struct ServerConnectView: View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
DefaultTextField("", text: $server.name, prompt: "Name")
|
if #available(iOS 15, *) {
|
||||||
|
TextField("", text: $server.name, prompt: Text("Name (optional)"))
|
||||||
|
} else {
|
||||||
|
DefaultTextField("", text: $server.name, prompt: "Name (optional)")
|
||||||
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("Name")
|
Text("Name")
|
||||||
}
|
}
|
||||||
|
@ -150,8 +154,19 @@ private struct ServerConnectView: View {
|
||||||
if server.endpoint != nil {
|
if server.endpoint != nil {
|
||||||
Text(server.hostname)
|
Text(server.hostname)
|
||||||
} else {
|
} else {
|
||||||
DefaultTextField("", text: $server.hostname, prompt: "Hostname or IP address")
|
if #available(iOS 15, *) {
|
||||||
NumberTextField("", number: $server.port, prompt: "Port")
|
TextField("", text: $server.hostname, prompt: Text("Hostname or IP address"))
|
||||||
|
.keyboardType(.asciiCapable)
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
.textInputAutocapitalization(.never)
|
||||||
|
TextField("", value: $server.port, format: .number.grouping(.never), prompt: Text("Port"))
|
||||||
|
.keyboardType(.decimalPad)
|
||||||
|
} else {
|
||||||
|
DefaultTextField("", text: $server.hostname, prompt: "Hostname or IP address")
|
||||||
|
.keyboardType(.asciiCapable)
|
||||||
|
.autocorrectionDisabled()
|
||||||
|
NumberTextField("", number: $server.port, prompt: "Port")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("Host")
|
Text("Host")
|
||||||
|
@ -202,7 +217,7 @@ private struct ServerConnectView: View {
|
||||||
} else {
|
} else {
|
||||||
Text("Connect")
|
Text("Connect")
|
||||||
}
|
}
|
||||||
}
|
}.disabled(server.hostname.isEmpty || !server.isAvailable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import Network
|
||||||
import SwiftConnect
|
import SwiftConnect
|
||||||
|
|
||||||
let service = "_utm_server._tcp"
|
let service = "_utm_server._tcp"
|
||||||
let defaultServerPort = 21589
|
|
||||||
|
|
||||||
actor UTMRemoteClient {
|
actor UTMRemoteClient {
|
||||||
let state: State
|
let state: State
|
||||||
|
@ -86,9 +85,7 @@ actor UTMRemoteClient {
|
||||||
func connect(_ server: State.SavedServer) async throws {
|
func connect(_ server: State.SavedServer) async throws {
|
||||||
var server = server
|
var server = server
|
||||||
var isSuccessful = false
|
var isSuccessful = false
|
||||||
guard let endpoint = server.endpoint else {
|
let endpoint = server.endpoint ?? NWEndpoint.hostPort(host: .init(server.hostname), port: .init(integerLiteral: UInt16(server.port ?? 0)))
|
||||||
throw ConnectionError.cannotFindEndpoint
|
|
||||||
}
|
|
||||||
try await keyManager.load()
|
try await keyManager.load()
|
||||||
let connection = try await Connection(endpoint: endpoint, identity: keyManager.identity)
|
let connection = try await Connection(endpoint: endpoint, identity: keyManager.identity)
|
||||||
defer {
|
defer {
|
||||||
|
@ -110,13 +107,17 @@ actor UTMRemoteClient {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
let peer = Peer(connection: connection, localInterface: local)
|
let peer = Peer(connection: connection, localInterface: local)
|
||||||
let remote = Remote(peer: peer, host: host)
|
let remote = Remote(peer: peer, host: host)
|
||||||
try await remote.handshake()
|
let device = try await remote.handshake()
|
||||||
self.server = remote
|
self.server = remote
|
||||||
await state.setConnected(true)
|
await state.setConnected(true)
|
||||||
if !server.shouldSavePassword {
|
if !server.shouldSavePassword {
|
||||||
server.password = nil
|
server.password = nil
|
||||||
}
|
}
|
||||||
|
if server.name.isEmpty {
|
||||||
|
server.name = server.hostname
|
||||||
|
}
|
||||||
server.lastSeen = Date()
|
server.lastSeen = Date()
|
||||||
|
server.model = device.model
|
||||||
await state.save(server: server)
|
await state.save(server: server)
|
||||||
isSuccessful = true
|
isSuccessful = true
|
||||||
}
|
}
|
||||||
|
@ -158,12 +159,11 @@ extension UTMRemoteClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
var isAvailable: Bool {
|
var isAvailable: Bool {
|
||||||
endpoint != nil || port != nil
|
endpoint != nil || (port != nil && port != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.hostname = ""
|
self.hostname = ""
|
||||||
self.port = defaultServerPort
|
|
||||||
self.name = ""
|
self.name = ""
|
||||||
self.lastSeen = Date()
|
self.lastSeen = Date()
|
||||||
self.fingerprint = ""
|
self.fingerprint = ""
|
||||||
|
@ -309,12 +309,13 @@ extension UTMRemoteClient {
|
||||||
peer.close()
|
peer.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func handshake() async throws {
|
func handshake() async throws -> MacDevice {
|
||||||
let reply = try await _handshake(parameters: .init(version: UTMRemoteMessageServer.version))
|
let reply = try await _handshake(parameters: .init(version: UTMRemoteMessageServer.version))
|
||||||
guard reply.version == UTMRemoteMessageServer.version else {
|
guard reply.version == UTMRemoteMessageServer.version else {
|
||||||
throw ClientError.versionMismatch
|
throw ClientError.versionMismatch
|
||||||
}
|
}
|
||||||
capabilities = reply.capabilities
|
capabilities = reply.capabilities
|
||||||
|
return MacDevice(model: reply.model)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listVirtualMachines() async throws -> [M.ListVirtualMachines.Information] {
|
func listVirtualMachines() async throws -> [M.ListVirtualMachines.Information] {
|
||||||
|
@ -445,7 +446,6 @@ extension UTMRemoteClient {
|
||||||
|
|
||||||
extension UTMRemoteClient {
|
extension UTMRemoteClient {
|
||||||
enum ConnectionError: LocalizedError {
|
enum ConnectionError: LocalizedError {
|
||||||
case cannotFindEndpoint
|
|
||||||
case cannotDetermineHost
|
case cannotDetermineHost
|
||||||
case cannotFindFingerprint
|
case cannotFindFingerprint
|
||||||
case passwordRequired
|
case passwordRequired
|
||||||
|
@ -455,8 +455,6 @@ extension UTMRemoteClient {
|
||||||
|
|
||||||
var errorDescription: String? {
|
var errorDescription: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .cannotFindEndpoint:
|
|
||||||
return NSLocalizedString("The server has disappeared.", comment: "UTMRemoteClient")
|
|
||||||
case .cannotDetermineHost:
|
case .cannotDetermineHost:
|
||||||
return NSLocalizedString("Failed to determine host name.", comment: "UTMRemoteClient")
|
return NSLocalizedString("Failed to determine host name.", comment: "UTMRemoteClient")
|
||||||
case .cannotFindFingerprint:
|
case .cannotFindFingerprint:
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
"location" : "https://github.com/utmapp/SwiftConnect",
|
"location" : "https://github.com/utmapp/SwiftConnect",
|
||||||
"state" : {
|
"state" : {
|
||||||
"branch" : "main",
|
"branch" : "main",
|
||||||
"revision" : "c6e84abcc1563a1ec6521d6649b5b918494539bc"
|
"revision" : "1ba2f10260ad46ddcdb3f8c0d44be385ff89f11f"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue