diff --git a/Sources/BackupFeature/Service/BackupService.swift b/Sources/BackupFeature/Service/BackupService.swift index c99e9446fc9ec9b54ef6593cc3acb484f4db95bb..8392f32865dfc4c3c586cc90a346295ec7ddb6aa 100644 --- a/Sources/BackupFeature/Service/BackupService.swift +++ b/Sources/BackupFeature/Service/BackupService.swift @@ -19,19 +19,26 @@ public final class BackupService { @KeyObject(.username, defaultValue: nil) var username: String? @KeyObject(.backupSettings, defaultValue: nil) var storedSettings: Data? + public var backupsPublisher: AnyPublisher<[CloudService: Fetch.Metadata], Never> { + backupSubject.eraseToAnyPublisher() + } + + public var connectedServicesPublisher: AnyPublisher<Set<CloudService>, Never> { + connectedServicesSubject.eraseToAnyPublisher() + } + public var settingsPublisher: AnyPublisher<CloudSettings, Never> { settings.handleEvents(receiveSubscription: { [weak self] _ in guard let self = self else { return } - self.settings.value.connectedServices = CloudFilesManager.all.linkedServices() - CloudFilesManager.all.lastBackups { [weak self] in - guard let self else { return } - self.settings.value.backups = $0 - } + self.connectedServicesSubject.send(CloudFilesManager.all.linkedServices()) + self.fetchBackupOnAllProviders() }).eraseToAnyPublisher() } private var connType: ConnectionType = .wifi private var cancellables = Set<AnyCancellable>() + private let connectedServicesSubject = CurrentValueSubject<Set<CloudService>, Never>([]) + private let backupSubject = CurrentValueSubject<[CloudService: Fetch.Metadata], Never>([:]) private lazy var settings = CurrentValueSubject<CloudSettings, Never>(.init(fromData: storedSettings)) public init() { @@ -167,10 +174,11 @@ public final class BackupService { CloudFilesManager.all[.sftp] = sftpManager do { - try sftpManager.fetch { + try sftpManager.fetch { [weak self] in + guard let self else { return } switch $0 { case .success(let metadata): - self.settings.value.backups[.sftp] = metadata + self.backupSubject.value[.sftp] = metadata case .failure(let error): print(">>> Error fetching sftp: \(error.localizedDescription)") } @@ -184,17 +192,31 @@ public final class BackupService { service: CloudService, presenting screen: UIViewController ) { - service.authorize(presenting: screen) { - switch $0 { - case .success: - self.settings.value.connectedServices = CloudFilesManager.all.linkedServices() - CloudFilesManager.all.lastBackups { [weak self] in - guard let self else { return } - self.settings.value.backups = $0 + guard let manager = CloudFilesManager.all[service] else { + print(">>> Tried to link/auth but the enabled service is not set") + return + } + do { + try manager.link(screen) { [weak self] in + guard let self else { return } + switch $0 { + case .success: + self.connectedServicesSubject.value.insert(service) + self.fetchBackupOnAllProviders() + case .failure(let error): + self.connectedServicesSubject.value.remove(service) + print(">>> Failed to link/auth \(service): \(error.localizedDescription)") } - case .failure(let error): - print(">>> Tried to authorize \(service) but failed: \(error.localizedDescription)") } + } catch { + print(">>> Exception trying to link/auth \(service): \(error.localizedDescription)") + } + } + + func fetchBackupOnAllProviders() { + CloudFilesManager.all.lastBackups { [weak self] in + guard let self else { return } + self.backupSubject.send($0) } } @@ -202,7 +224,6 @@ public final class BackupService { guard let enabledService = settings.value.enabledService else { fatalError(">>> Trying to backup but nothing is enabled") } - if enabledService == .sftp { let keychain = Keychain(service: "SFTP-XXM") guard let host = try? keychain.get("host"), @@ -210,7 +231,6 @@ public final class BackupService { let username = try? keychain.get("username") else { fatalError(">>> Tried to perform an sftp backup but its not configured") } - CloudFilesManager.all[.sftp] = .sftp( host: host, username: username, @@ -218,17 +238,26 @@ public final class BackupService { fileName: "backup.xxm" ) } + guard let manager = CloudFilesManager.all[enabledService] else { + print(">>> Tried to upload but the enabled service is not set") + return + } + do { + try manager.upload(data) { [weak self] in + guard let self else { return } - enabledService.backup(data: data) { - switch $0 { - case .success(let metadata): - self.settings.value.backups[enabledService] = .init( - size: metadata.size, - lastModified: metadata.lastModified - ) - case .failure(let error): - print(">>> Failed to perform a backup upload: \(error.localizedDescription)") + switch $0 { + case .success(let metadata): + self.backupSubject.value[enabledService] = .init( + size: metadata.size, + lastModified: metadata.lastModified + ) + case .failure(let error): + print(">>> Failed to perform a backup upload: \(error.localizedDescription)") + } } + } catch { + print(">>> Exception performing a backup upload: \(error.localizedDescription)") } } diff --git a/Sources/BackupFeature/ViewModels/BackupConfigViewModel.swift b/Sources/BackupFeature/ViewModels/BackupConfigViewModel.swift index 6d5daa394016276b431fe1ea1b218d9eade1e23a..569a65de8bd272ccb06cbd661e1e5bc1f7015d2a 100644 --- a/Sources/BackupFeature/ViewModels/BackupConfigViewModel.swift +++ b/Sources/BackupFeature/ViewModels/BackupConfigViewModel.swift @@ -89,9 +89,10 @@ extension BackupConfigViewModel { }, lastBackup: { context.service.settingsPublisher - .map { - guard let enabledService = $0.enabledService else { return nil } - return $0.backups[enabledService] + .combineLatest(context.service.backupsPublisher) + .map { settings, backups in + guard let enabled = settings.enabledService else { return nil } + return backups[enabled] }.eraseToAnyPublisher() }, actionState: { @@ -106,8 +107,7 @@ extension BackupConfigViewModel { .eraseToAnyPublisher() }, connectedServices: { - context.service.settingsPublisher - .map(\.connectedServices) + context.service.connectedServicesPublisher .removeDuplicates() .eraseToAnyPublisher() } diff --git a/Sources/BackupFeature/ViewModels/BackupViewModel.swift b/Sources/BackupFeature/ViewModels/BackupViewModel.swift index 6522ee1215a4ee84000c85600389bf53d52aa9bc..23c4cc9d7d617380b8c3b3c35ceb5e65ac569493 100644 --- a/Sources/BackupFeature/ViewModels/BackupViewModel.swift +++ b/Sources/BackupFeature/ViewModels/BackupViewModel.swift @@ -25,8 +25,7 @@ extension BackupViewModel { setupViewModel: { BackupSetupViewModel.live() }, configViewModel: { BackupConfigViewModel.live() }, state: { - context.service.settingsPublisher - .map(\.connectedServices) + context.service.connectedServicesPublisher .map { $0.isEmpty ? BackupViewState.setup : .config } .eraseToAnyPublisher() }