import Bindings public struct ClientStorage { public var hasStoredClient: () -> Bool public var createClient: () throws -> Client public var loadClient: () throws -> Client public var removeClient: () throws -> Void } extension ClientStorage { public static let defaultDirectoryURL = FileManager.default .urls(for: .applicationSupportDirectory, in: .userDomainMask) .first! .appendingPathComponent("xx.network.client") public static func live( environment: Environment = .mainnet, directoryURL: URL = defaultDirectoryURL, fileManager: FileManager = .default, generatePassword: PasswordGenerator = .live, passwordStorage: PasswordStorage, downloadNDF: NDFDownloader = .live, createClient: ClientCreator = .live, loadClient: ClientLoader = .live ) -> ClientStorage { ClientStorage( hasStoredClient: { let contents = try? fileManager.contentsOfDirectory(atPath: directoryURL.path) return contents.map { $0.isEmpty == false } ?? false }, createClient: { let ndf = try downloadNDF(environment) let password = generatePassword() try passwordStorage.save(password) try? fileManager.removeItem(at: directoryURL) try? fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true) try createClient(directoryURL: directoryURL, ndf: ndf, password: password) return try loadClient(directoryURL: directoryURL, password: password) }, loadClient: { let password = try passwordStorage.load() return try loadClient(directoryURL: directoryURL, password: password) }, removeClient: { try fileManager.removeItem(at: directoryURL) } ) } } #if DEBUG extension ClientStorage { public static let failing = ClientStorage( hasStoredClient: { false }, createClient: { struct NotImplemented: Error {} throw NotImplemented() }, loadClient: { struct NotImplemented: Error {} throw NotImplemented() }, removeClient: { struct NotImplemented: Error {} throw NotImplemented() } ) } #endif