@braedonsaunders/appkit-desk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -1
- package/backend.d.ts +4 -0
- package/backend.d.ts.map +1 -1
- package/backend.js +92 -6
- package/backend.js.map +1 -1
- package/host.d.ts +24 -1
- package/host.d.ts.map +1 -1
- package/host.js +17 -4
- package/host.js.map +1 -1
- package/machine.d.ts +10 -1
- package/machine.d.ts.map +1 -1
- package/machine.js +55 -0
- package/machine.js.map +1 -1
- package/package.json +1 -1
- package/plan.d.ts +63 -0
- package/plan.d.ts.map +1 -1
- package/plan.js +133 -3
- package/plan.js.map +1 -1
- package/virtualization.d.ts.map +1 -1
- package/virtualization.js +9 -1
- package/virtualization.js.map +1 -1
- package/vz/Sources/appkit-desk-vz/Helper.swift +45 -0
|
@@ -2,6 +2,13 @@ import DeskNet
|
|
|
2
2
|
import Foundation
|
|
3
3
|
import Virtualization
|
|
4
4
|
|
|
5
|
+
/// A host directory shared into the guest over virtio-fs.
|
|
6
|
+
struct ShareRequest {
|
|
7
|
+
let tag: String
|
|
8
|
+
let directory: URL
|
|
9
|
+
let readOnly: Bool
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
/// Everything `boot` needs, validated before anything is created.
|
|
6
13
|
struct BootRequest {
|
|
7
14
|
let kernel: URL
|
|
@@ -16,6 +23,7 @@ struct BootRequest {
|
|
|
16
23
|
let machineIdentifier: Data?
|
|
17
24
|
let consoleLog: URL?
|
|
18
25
|
let network: NetworkConfiguration
|
|
26
|
+
let shares: [ShareRequest]
|
|
19
27
|
|
|
20
28
|
init(_ body: [String: Any]) throws {
|
|
21
29
|
kernel = URL(fileURLWithPath: try body.path("kernel"))
|
|
@@ -39,6 +47,7 @@ struct BootRequest {
|
|
|
39
47
|
if restoreFrom != nil && machineIdentifier == nil {
|
|
40
48
|
throw RequestError("restoreFrom requires the machineIdentifier the machine was saved with.")
|
|
41
49
|
}
|
|
50
|
+
shares = try Self.shares(body["shares"])
|
|
42
51
|
|
|
43
52
|
let network = (body["network"] as? [String: Any]) ?? [:]
|
|
44
53
|
var configuration = NetworkConfiguration(allowLan: try network.bool("allowLan", default: false))
|
|
@@ -74,6 +83,27 @@ struct BootRequest {
|
|
|
74
83
|
}
|
|
75
84
|
self.network = configuration
|
|
76
85
|
}
|
|
86
|
+
|
|
87
|
+
/// Tags are checked against Virtualization.framework's own rules when the
|
|
88
|
+
/// devices are made; here, only that each is present and unique.
|
|
89
|
+
private static func shares(_ value: Any?) throws -> [ShareRequest] {
|
|
90
|
+
guard let value, !(value is NSNull) else { return [] }
|
|
91
|
+
guard let entries = value as? [[String: Any]] else { throw RequestError("shares must be an array of objects.") }
|
|
92
|
+
var tags = Set<String>()
|
|
93
|
+
return try entries.enumerated().map { index, entry in
|
|
94
|
+
let tag = try entry.string("tag")
|
|
95
|
+
guard tags.insert(tag).inserted else { throw RequestError("shares[\(index)].tag \(tag) is used by another share.") }
|
|
96
|
+
let path = try entry.path("path")
|
|
97
|
+
var isDirectory: ObjCBool = false
|
|
98
|
+
guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory), isDirectory.boolValue else {
|
|
99
|
+
throw RequestError("shares[\(index)].path is not an existing directory: \(path)")
|
|
100
|
+
}
|
|
101
|
+
guard entry["readOnly"] is NSNumber else { throw RequestError("shares[\(index)].readOnly must be a boolean.") }
|
|
102
|
+
return ShareRequest(
|
|
103
|
+
tag: tag, directory: URL(fileURLWithPath: path, isDirectory: true),
|
|
104
|
+
readOnly: try entry.bool("readOnly", default: false))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
77
107
|
}
|
|
78
108
|
|
|
79
109
|
/// One helper process runs one VM. It owns the VM, the guest's network, and
|
|
@@ -332,6 +362,21 @@ final class Helper: NSObject, VZVirtualMachineDelegate {
|
|
|
332
362
|
network.guestMAC = MAC(nic.macAddress.string) ?? network.guestMAC
|
|
333
363
|
attachNetwork(network, fd: helperEnd)
|
|
334
364
|
|
|
365
|
+
// Built from the request on every boot, so a restore has exactly the
|
|
366
|
+
// devices the machine was saved with as long as the host asks for the same
|
|
367
|
+
// shares — which it checks before restoring.
|
|
368
|
+
configuration.directorySharingDevices = try request.shares.map { share in
|
|
369
|
+
do {
|
|
370
|
+
try VZVirtioFileSystemDeviceConfiguration.validateTag(share.tag)
|
|
371
|
+
} catch {
|
|
372
|
+
throw RequestError("Share tag \(share.tag) is not a valid virtio-fs tag: \(describe(error))")
|
|
373
|
+
}
|
|
374
|
+
let device = VZVirtioFileSystemDeviceConfiguration(tag: share.tag)
|
|
375
|
+
device.share = VZSingleDirectoryShare(
|
|
376
|
+
directory: VZSharedDirectory(url: share.directory, readOnly: share.readOnly))
|
|
377
|
+
return device
|
|
378
|
+
}
|
|
379
|
+
|
|
335
380
|
configuration.entropyDevices = [VZVirtioEntropyDeviceConfiguration()]
|
|
336
381
|
configuration.memoryBalloonDevices = [VZVirtioTraditionalMemoryBalloonDeviceConfiguration()]
|
|
337
382
|
configuration.socketDevices = [VZVirtioSocketDeviceConfiguration()]
|