remote: implement ReorderVirtualMachines and GetPackageSize
This commit is contained in:
parent
db038df8e2
commit
452f8c2088
|
@ -30,8 +30,9 @@ struct VMDetailsView: View {
|
|||
private let regularScreenSizeClass: Bool = true
|
||||
#endif
|
||||
|
||||
@State private var size: Int64 = 0
|
||||
|
||||
private var sizeLabel: String {
|
||||
let size = data.computeSize(for: vm)
|
||||
return ByteCountFormatter.string(fromByteCount: size, countStyle: .binary)
|
||||
}
|
||||
|
||||
|
@ -109,6 +110,11 @@ struct VMDetailsView: View {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
.onAppear {
|
||||
Task {
|
||||
size = await data.computeSize(for: vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -549,7 +549,7 @@ struct AlertMessage: Identifiable {
|
|||
/// Calculate total size of VM and data
|
||||
/// - Parameter vm: VM to calculate size
|
||||
/// - Returns: Size in bytes
|
||||
func computeSize(for vm: VMData) -> Int64 {
|
||||
func computeSize(for vm: VMData) async -> Int64 {
|
||||
let path = vm.pathUrl
|
||||
guard let enumerator = fileManager.enumerator(at: path, includingPropertiesForKeys: [.totalFileAllocatedSizeKey]) else {
|
||||
logger.error("failed to create enumerator for \(path)")
|
||||
|
@ -633,7 +633,7 @@ struct AlertMessage: Identifiable {
|
|||
listSelect(vm: vm)
|
||||
}
|
||||
|
||||
func copyItemWithCopyfile(at srcURL: URL, to dstURL: URL) async throws {
|
||||
private func copyItemWithCopyfile(at srcURL: URL, to dstURL: URL) async throws {
|
||||
try await Task.detached(priority: .userInitiated) {
|
||||
let status = copyfile(srcURL.path, dstURL.path, nil, copyfile_flags_t(COPYFILE_ALL | COPYFILE_RECURSIVE | COPYFILE_CLONE | COPYFILE_DATA_SPARSE))
|
||||
if status < 0 {
|
||||
|
@ -999,6 +999,7 @@ enum UTMDataError: Error {
|
|||
case jitStreamerDecodeFailed
|
||||
case jitStreamerAttachFailed
|
||||
case jitStreamerUrlInvalid(String)
|
||||
case notImplemented
|
||||
}
|
||||
|
||||
extension UTMDataError: LocalizedError {
|
||||
|
@ -1028,6 +1029,8 @@ extension UTMDataError: LocalizedError {
|
|||
return NSLocalizedString("Failed to attach to JitStreamer.", comment: "UTMData")
|
||||
case .jitStreamerUrlInvalid(let urlString):
|
||||
return String.localizedStringWithFormat(NSLocalizedString("Invalid JitStreamer attach URL:\n%@", comment: "UTMData"), urlString)
|
||||
case .notImplemented:
|
||||
return NSLocalizedString("This functionality is not yet implemented.", comment: "UTMData")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1122,5 +1125,59 @@ class UTMRemoteData: UTMData {
|
|||
session.fatalError = message
|
||||
}
|
||||
}
|
||||
|
||||
override func listMove(fromOffsets: IndexSet, toOffset: Int) {
|
||||
let ids = fromOffsets.map({ virtualMachines[$0].id })
|
||||
Task {
|
||||
try await remoteClient.server.reorderVirtualMachines(fromIds: ids, toOffset: toOffset)
|
||||
}
|
||||
super.listMove(fromOffsets: fromOffsets, toOffset: toOffset)
|
||||
}
|
||||
|
||||
override func save(vm: VMData) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func discardChanges(for vm: VMData) throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func create<Config: UTMConfiguration>(config: Config) async throws -> VMData {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
override func delete(vm: VMData, alsoRegistry: Bool) async throws -> Int? {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
override func clone(vm: VMData) async throws -> VMData {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func export(vm: VMData, to url: URL) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func move(vm: VMData, to url: URL) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func template(vm: VMData) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func computeSize(for vm: VMData) async -> Int64 {
|
||||
(try? await remoteClient.server.getPackageSize(for: vm.id)) ?? 0
|
||||
}
|
||||
|
||||
override func importUTM(from url: URL, asShortcut: Bool) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
|
||||
override func mountSupportTools(for vm: any UTMVirtualMachine) async throws {
|
||||
throw UTMDataError.notImplemented
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -333,10 +333,18 @@ extension UTMRemoteClient {
|
|||
try await _listVirtualMachines(parameters: .init()).items
|
||||
}
|
||||
|
||||
func reorderVirtualMachines(fromIds ids: [UUID], toOffset offset: Int) async throws {
|
||||
try await _reorderVirtualMachines(parameters: .init(ids: ids, offset: offset))
|
||||
}
|
||||
|
||||
func getQEMUConfiguration(for id: UUID) async throws -> UTMQemuConfiguration {
|
||||
try await _getQEMUConfiguration(parameters: .init(id: id)).configuration
|
||||
}
|
||||
|
||||
func getPackageSize(for id: UUID) async throws -> Int64 {
|
||||
try await _getPackageSize(parameters: .init(id: id)).size
|
||||
}
|
||||
|
||||
func getPackageDataFile(for id: UUID, name: String) async throws -> URL {
|
||||
let fm = FileManager.default
|
||||
let cacheUrl = try fm.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||||
|
@ -400,10 +408,19 @@ extension UTMRemoteClient {
|
|||
try await M.ListVirtualMachines.send(parameters, to: peer)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func _reorderVirtualMachines(parameters: M.ReorderVirtualMachines.Request) async throws -> M.ReorderVirtualMachines.Reply {
|
||||
try await M.ReorderVirtualMachines.send(parameters, to: peer)
|
||||
}
|
||||
|
||||
private func _getQEMUConfiguration(parameters: M.GetQEMUConfiguration.Request) async throws -> M.GetQEMUConfiguration.Reply {
|
||||
try await M.GetQEMUConfiguration.send(parameters, to: peer)
|
||||
}
|
||||
|
||||
private func _getPackageSize(parameters: M.GetPackageSize.Request) async throws -> M.GetPackageSize.Reply {
|
||||
try await M.GetPackageSize.send(parameters, to: peer)
|
||||
}
|
||||
|
||||
private func _getPackageDataFile(parameters: M.GetPackageDataFile.Request) async throws -> M.GetPackageDataFile.Reply {
|
||||
try await M.GetPackageDataFile.send(parameters, to: peer)
|
||||
}
|
||||
|
|
|
@ -21,8 +21,9 @@ enum UTMRemoteMessageServer: UInt8, MessageID {
|
|||
static let version = 1
|
||||
case serverHandshake
|
||||
case listVirtualMachines
|
||||
case reorderVirtualMachines
|
||||
case getQEMUConfiguration
|
||||
case updateQEMUConfiguration
|
||||
case getPackageSize
|
||||
case getPackageDataFile
|
||||
case startVirtualMachine
|
||||
case stopVirtualMachine
|
||||
|
@ -83,6 +84,17 @@ extension UTMRemoteMessageServer {
|
|||
}
|
||||
}
|
||||
|
||||
struct ReorderVirtualMachines: Message {
|
||||
static let id = UTMRemoteMessageServer.reorderVirtualMachines
|
||||
|
||||
struct Request: Serializable, Codable {
|
||||
let ids: [UUID]
|
||||
let offset: Int
|
||||
}
|
||||
|
||||
struct Reply: Serializable, Codable {}
|
||||
}
|
||||
|
||||
struct GetQEMUConfiguration: Message {
|
||||
static let id = UTMRemoteMessageServer.getQEMUConfiguration
|
||||
|
||||
|
@ -95,16 +107,16 @@ extension UTMRemoteMessageServer {
|
|||
}
|
||||
}
|
||||
|
||||
struct UpdateQEMUConfiguration: Message {
|
||||
static let id = UTMRemoteMessageServer.updateQEMUConfiguration
|
||||
struct GetPackageSize: Message {
|
||||
static let id = UTMRemoteMessageServer.getPackageSize
|
||||
|
||||
struct Request: Serializable, Codable {
|
||||
let id: UUID
|
||||
let configuration: UTMQemuConfiguration
|
||||
let files: [String: Data]
|
||||
}
|
||||
|
||||
struct Reply: Serializable, Codable {}
|
||||
struct Reply: Serializable, Codable {
|
||||
let size: Int64
|
||||
}
|
||||
}
|
||||
|
||||
struct GetPackageDataFile: Message {
|
||||
|
|
|
@ -608,10 +608,12 @@ extension UTMRemoteServer {
|
|||
return try await _handshake(parameters: .decode(data)).encode()
|
||||
case .listVirtualMachines:
|
||||
return try await _listVirtualMachines(parameters: .decode(data)).encode()
|
||||
case .reorderVirtualMachines:
|
||||
return try await _reorderVirtualMachines(parameters: .decode(data)).encode()
|
||||
case .getQEMUConfiguration:
|
||||
return try await _getQEMUConfiguration(parameters: .decode(data)).encode()
|
||||
case .updateQEMUConfiguration:
|
||||
return try await _updateQEMUConfiguration(parameters: .decode(data)).encode()
|
||||
case .getPackageSize:
|
||||
return try await _getPackageSize(parameters: .decode(data)).encode()
|
||||
case .getPackageDataFile:
|
||||
return try await _getPackageDataFile(parameters: .decode(data)).encode()
|
||||
case .startVirtualMachine:
|
||||
|
@ -679,6 +681,20 @@ extension UTMRemoteServer {
|
|||
return .init(items: items)
|
||||
}
|
||||
|
||||
private func _reorderVirtualMachines(parameters: M.ReorderVirtualMachines.Request) async throws -> M.ReorderVirtualMachines.Reply {
|
||||
await Task { @MainActor in
|
||||
let vms = data.virtualMachines
|
||||
let source = parameters.ids.reduce(into: IndexSet(), { indexSet, id in
|
||||
if let index = vms.firstIndex(where: { $0.id == id }) {
|
||||
indexSet.insert(index)
|
||||
}
|
||||
})
|
||||
let destination = min(max(0, parameters.offset), vms.count)
|
||||
data.listMove(fromOffsets: source, toOffset: destination)
|
||||
return .init()
|
||||
}.value
|
||||
}
|
||||
|
||||
private func _getQEMUConfiguration(parameters: M.GetQEMUConfiguration.Request) async throws -> M.GetQEMUConfiguration.Reply {
|
||||
let vm = try await findVM(withId: parameters.id)
|
||||
if let config = await vm.config as? UTMQemuConfiguration {
|
||||
|
@ -688,8 +704,10 @@ extension UTMRemoteServer {
|
|||
}
|
||||
}
|
||||
|
||||
private func _updateQEMUConfiguration(parameters: M.UpdateQEMUConfiguration.Request) async throws -> M.UpdateQEMUConfiguration.Reply {
|
||||
return .init()
|
||||
private func _getPackageSize(parameters: M.GetPackageSize.Request) async throws -> M.GetPackageSize.Reply {
|
||||
let vm = try await findVM(withId: parameters.id)
|
||||
let size = await data.computeSize(for: vm)
|
||||
return .init(size: size)
|
||||
}
|
||||
|
||||
private func _getPackageDataFile(parameters: M.GetPackageDataFile.Request) async throws -> M.GetPackageDataFile.Reply {
|
||||
|
|
Loading…
Reference in New Issue