From 216a7eb4c2dee478ca56ed95ea5f79f33e928ae8 Mon Sep 17 00:00:00 2001 From: wuyueyang Date: Wed, 14 Jun 2023 17:04:49 +0800 Subject: [PATCH] Prevent system from deleting caches while app is running --- .../DeviceTransfer/DeviceTransferClient.swift | 29 ++++++++++--------- .../DeviceTransfer/DeviceTransferError.swift | 1 - .../RestoreFromDesktopViewController.swift | 27 ++++++++++------- Mixin/UserInterface/Windows/UrlWindow.swift | 27 ++++++++++------- 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/Mixin/Service/DeviceTransfer/DeviceTransferClient.swift b/Mixin/Service/DeviceTransfer/DeviceTransferClient.swift index d1434e71bf..2e1694e9d7 100644 --- a/Mixin/Service/DeviceTransfer/DeviceTransferClient.swift +++ b/Mixin/Service/DeviceTransfer/DeviceTransferClient.swift @@ -21,10 +21,10 @@ final class DeviceTransferClient { private let key: DeviceTransferKey private let remotePlatform: DeviceTransferPlatform private let connection: NWConnection + private let cacheContainerURL: URL + private let messageProcessor: DeviceTransferMessageProcessor private let queue = Queue(label: "one.mixin.messenger.DeviceTransferClient") - private let cacheContainerURL = FileManager.default.temporaryDirectory.appendingPathComponent("DeviceTransfer", isDirectory: true) private let speedInspector = NetworkSpeedInspector() - private let messageProcessor: DeviceTransferMessageProcessor private weak var statisticsTimer: Timer? @@ -40,7 +40,18 @@ final class DeviceTransferClient { Unmanaged.passUnretained(self).toOpaque() } - init(hostname: String, port: UInt16, code: UInt16, key: DeviceTransferKey, remotePlatform: DeviceTransferPlatform) { + init(hostname: String, port: UInt16, code: UInt16, key: DeviceTransferKey, remotePlatform: DeviceTransferPlatform) throws { + // https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW2 + // In iOS 5.0 and later, the system may delete the Caches directory on rare occasions when the system is very low on disk space. + // This will never occur while an app is running. + let manager = FileManager.default + let cacheContainerURL = try manager.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + .appendingPathComponent("DeviceTransfer") + if manager.fileExists(atPath: cacheContainerURL.path) { + try? manager.removeItem(at: cacheContainerURL) + } + try manager.createDirectory(at: cacheContainerURL, withIntermediateDirectories: true) + self.hostname = hostname self.port = port self.code = code @@ -52,6 +63,7 @@ final class DeviceTransferClient { let endpoint = NWEndpoint.hostPort(host: host, port: port) return NWConnection(to: endpoint, using: .deviceTransfer) }() + self.cacheContainerURL = cacheContainerURL self.messageProcessor = .init(key: key.aes, remotePlatform: remotePlatform, cacheContainerURL: cacheContainerURL, @@ -65,17 +77,6 @@ final class DeviceTransferClient { func start() { Logger.general.info(category: "DeviceTransferClient", message: "Will start connecting to [\(hostname)]:\(port)") - do { - let manager = FileManager.default - if manager.fileExists(atPath: cacheContainerURL.path) { - try? manager.removeItem(at: cacheContainerURL) - } - try manager.createDirectory(at: cacheContainerURL, withIntermediateDirectories: true) - } catch { - Logger.general.error(category: "DeviceTransferClient", message: "Failed to create cache container: \(error)") - fail(error: .createCacheContainer(error)) - return - } messageProcessor.$processingError .receive(on: queue.dispatchQueue) .sink { error in diff --git a/Mixin/Service/DeviceTransfer/DeviceTransferError.swift b/Mixin/Service/DeviceTransfer/DeviceTransferError.swift index 017e71847d..5af46cc258 100644 --- a/Mixin/Service/DeviceTransfer/DeviceTransferError.swift +++ b/Mixin/Service/DeviceTransfer/DeviceTransferError.swift @@ -7,6 +7,5 @@ enum DeviceTransferError: Error { case mismatchedHMAC(local: Data, remote: Data) case connectionFailed(Error) case receiveFile(Error) - case createCacheContainer(Error) case importing(DeviceTransferMessageProcessor.ProcessingError) } diff --git a/Mixin/UserInterface/Controllers/DeviceTransfer/RestoreFromDesktopViewController.swift b/Mixin/UserInterface/Controllers/DeviceTransfer/RestoreFromDesktopViewController.swift index a7957e9790..45c23b48e5 100644 --- a/Mixin/UserInterface/Controllers/DeviceTransfer/RestoreFromDesktopViewController.swift +++ b/Mixin/UserInterface/Controllers/DeviceTransfer/RestoreFromDesktopViewController.swift @@ -119,17 +119,24 @@ extension RestoreFromDesktopViewController { dataSource.replaceSection(at: 0, with: section, animation: .automatic) tableView.isUserInteractionEnabled = true case let .push(context): - let client = DeviceTransferClient(hostname: context.hostname, - port: context.port, - code: context.code, - key: context.key, - remotePlatform: command.platform) - stateObserver = client.$state - .receive(on: DispatchQueue.main) - .sink { [weak self] state in - self?.stateDidChange(client: client, state: state) + do { + let client = try DeviceTransferClient(hostname: context.hostname, + port: context.port, + code: context.code, + key: context.key, + remotePlatform: command.platform) + stateObserver = client.$state + .receive(on: DispatchQueue.main) + .sink { [weak self] state in + self?.stateDidChange(client: client, state: state) + } + client.start() + } catch { + Logger.general.error(category: "RestoreFromDesktop", message: "Unable to init client: \(error)") + alert(R.string.localizable.connection_establishment_failed(), message: nil) { _ in + self.navigationController?.popViewController(animated: true) } - client.start() + } default: Logger.general.info(category: "RestoreFromDesktop", message: "Invalid command") alert(R.string.localizable.connection_establishment_failed(), message: nil) { _ in diff --git a/Mixin/UserInterface/Windows/UrlWindow.swift b/Mixin/UserInterface/Windows/UrlWindow.swift index 2697ea8258..2de79dad94 100644 --- a/Mixin/UserInterface/Windows/UrlWindow.swift +++ b/Mixin/UserInterface/Windows/UrlWindow.swift @@ -888,17 +888,22 @@ class UrlWindow { UIApplication.currentActivity()?.alert(R.string.localizable.unable_synced_between_different_account()) return true } - let client = DeviceTransferClient(hostname: context.hostname, - port: context.port, - code: context.code, - key: context.key, - remotePlatform: command.platform) - client.start() - let progress = DeviceTransferProgressViewController(connection: .client(client, .phone)) - if let navigationController = AppDelegate.current.mainWindow.rootViewController as? UINavigationController { - navigationController.pushViewController(progress, animated: true) - } else { - AppDelegate.current.mainWindow.rootViewController?.present(progress, animated: true) + do { + let client = try DeviceTransferClient(hostname: context.hostname, + port: context.port, + code: context.code, + key: context.key, + remotePlatform: command.platform) + client.start() + let progress = DeviceTransferProgressViewController(connection: .client(client, .phone)) + if let navigationController = AppDelegate.current.mainWindow.rootViewController as? UINavigationController { + navigationController.pushViewController(progress, animated: true) + } else { + AppDelegate.current.mainWindow.rootViewController?.present(progress, animated: true) + } + } catch { + Logger.general.error(category: "UrlWindow", message: "Unable to init client: \(error)") + UIApplication.currentActivity()?.alert(R.string.localizable.connection_establishment_failed()) } return true }