Преглед изворни кода

remote: implement ReorderVirtualMachines and GetPackageSize

osy пре 1 година
родитељ
комит
452f8c2088

+ 8 - 2
Platform/Shared/VMDetailsView.swift

@@ -29,9 +29,10 @@ struct VMDetailsView: View {
     #else
     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)
+                }
+            }
         }
     }
 }

+ 59 - 2
Platform/UTMData.swift

@@ -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

+ 17 - 0
Remote/UTMRemoteClient.swift

@@ -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)
         }

+ 18 - 6
Remote/UTMRemoteMessage.swift

@@ -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 {

+ 22 - 4
Remote/UTMRemoteServer.swift

@@ -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 {