Encapsulate *Persistence responsibilities (#305)

Do not leave the choice of a repository context up to the library
consumer. Instead, provide a specific factory (*Persistence) for each
module.
This commit is contained in:
Davide De Rosa 2023-05-27 12:32:53 +02:00 committed by GitHub
parent efcda495bc
commit a78a7b18b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 40 deletions

View File

@ -33,18 +33,18 @@ import TunnelKitManager
final class CoreContext { final class CoreContext {
let store: KeyValueStore let store: KeyValueStore
private let profilesPersistence: CoreDataPersistentStore private let providersPersistence: ProvidersPersistence
private let providersPersistence: CoreDataPersistentStore private let vpnPersistence: VPNPersistence
var urlsForProfiles: [URL]? {
profilesPersistence.containerURLs
}
var urlsForProviders: [URL]? { var urlsForProviders: [URL]? {
providersPersistence.containerURLs providersPersistence.containerURLs
} }
var urlsForProfiles: [URL]? {
vpnPersistence.containerURLs
}
let upgradeManager: UpgradeManager let upgradeManager: UpgradeManager
let providerManager: ProviderManager let providerManager: ProviderManager
@ -67,7 +67,7 @@ final class CoreContext {
pp_log.info("Logging to: \(logger.logFile!)") pp_log.info("Logging to: \(logger.logFile!)")
let persistenceManager = PersistenceManager(store: store) let persistenceManager = PersistenceManager(store: store)
profilesPersistence = persistenceManager.profilesPersistence( vpnPersistence = persistenceManager.vpnPersistence(
withName: Constants.Persistence.profilesContainerName withName: Constants.Persistence.profilesContainerName
) )
providersPersistence = persistenceManager.providersPersistence( providersPersistence = persistenceManager.providersPersistence(
@ -89,17 +89,17 @@ final class CoreContext {
Constants.Repos.api, Constants.Repos.api,
timeout: Constants.Services.connectivityTimeout timeout: Constants.Services.connectivityTimeout
), ),
webServicesRepository: PassepartoutPersistence.webServicesRepository(providersPersistence) webServicesRepository: providersPersistence.webServicesRepository()
) )
providerManager = ProviderManager( providerManager = ProviderManager(
localProvidersRepository: PassepartoutPersistence.localProvidersRepository(providersPersistence), localProvidersRepository: providersPersistence.localProvidersRepository(),
remoteProvidersStrategy: remoteProvidersStrategy remoteProvidersStrategy: remoteProvidersStrategy
) )
profileManager = ProfileManager( profileManager = ProfileManager(
store: store, store: store,
providerManager: providerManager, providerManager: providerManager,
profileRepository: PassepartoutPersistence.profileRepository(profilesPersistence), profileRepository: vpnPersistence.profileRepository(),
keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId), keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId),
keychainEntry: Unlocalized.Keychain.passwordEntry, keychainEntry: Unlocalized.Keychain.passwordEntry,
keychainLabel: Unlocalized.Keychain.passwordLabel keychainLabel: Unlocalized.Keychain.passwordLabel

View File

@ -39,12 +39,12 @@ final class PersistenceManager {
} }
} }
func profilesPersistence(withName containerName: String) -> CoreDataPersistentStore { func vpnPersistence(withName containerName: String) -> VPNPersistence {
PassepartoutPersistence.profilesStore(withName: containerName, cloudKit: true, author: persistenceAuthor) VPNPersistence(withName: containerName, cloudKit: true, author: persistenceAuthor)
} }
func providersPersistence(withName containerName: String) -> CoreDataPersistentStore { func providersPersistence(withName containerName: String) -> ProvidersPersistence {
PassepartoutPersistence.providersStore(withName: containerName, cloudKit: false, author: persistenceAuthor) ProvidersPersistence(withName: containerName, cloudKit: false, author: persistenceAuthor)
} }
} }

View File

@ -35,9 +35,6 @@ public class Passepartout {
public var logger: Logger = DefaultLogger() public var logger: Logger = DefaultLogger()
} }
public enum PassepartoutPersistence {
}
public struct PassepartoutError: Error, Equatable { public struct PassepartoutError: Error, Equatable {
private let string: String private let string: String

View File

@ -1,5 +1,5 @@
// //
// Persistence.swift // ProvidersPersistence.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 4/7/22. // Created by Davide De Rosa on 4/7/22.
@ -29,30 +29,34 @@ import PassepartoutCore
import PassepartoutProviders import PassepartoutProviders
import PassepartoutServices import PassepartoutServices
extension PassepartoutPersistence { public final class ProvidersPersistence {
private static let providersDataModel: NSManagedObjectModel = { private static let dataModel: NSManagedObjectModel = {
guard let model = NSManagedObjectModel.mergedModel(from: [.module]) else { guard let model = NSManagedObjectModel.mergedModel(from: [.module]) else {
fatalError("Could not load PassepartoutProviders model") fatalError("Could not load PassepartoutProviders model")
} }
return model return model
}() }()
public static func providersStore(withName containerName: String, cloudKit: Bool, author: String?) -> CoreDataPersistentStore { private let store: CoreDataPersistentStore
.init(
public var containerURLs: [URL]? {
store.containerURLs
}
public init(withName containerName: String, cloudKit: Bool, author: String?) {
store = .init(
withName: containerName, withName: containerName,
model: providersDataModel, model: Self.dataModel,
cloudKit: cloudKit, cloudKit: cloudKit,
author: author author: author
) )
} }
}
extension PassepartoutPersistence { public func webServicesRepository() -> WebServicesRepository {
public static func webServicesRepository(_ store: CoreDataPersistentStore) -> WebServicesRepository {
CDWebServicesRepository(store.context) CDWebServicesRepository(store.context)
} }
public static func localProvidersRepository(_ store: CoreDataPersistentStore) -> LocalProvidersRepository { public func localProvidersRepository() -> LocalProvidersRepository {
CDLocalProvidersRepository(store.context) CDLocalProvidersRepository(store.context)
} }
} }

View File

@ -1,5 +1,5 @@
// //
// Persistence.swift // VPNPersistence.swift
// Passepartout // Passepartout
// //
// Created by Davide De Rosa on 4/7/22. // Created by Davide De Rosa on 4/7/22.
@ -28,25 +28,30 @@ import Foundation
import PassepartoutCore import PassepartoutCore
import PassepartoutVPN import PassepartoutVPN
extension PassepartoutPersistence { public final class VPNPersistence {
private static let profilesDataModel: NSManagedObjectModel = { private static let dataModel: NSManagedObjectModel = {
guard let model = NSManagedObjectModel.mergedModel(from: [.module]) else { guard let model = NSManagedObjectModel.mergedModel(from: [.module]) else {
fatalError("Could not load PassepartoutProfiles model") fatalError("Could not load PassepartoutProfiles model")
} }
return model return model
}() }()
public static func profilesStore(withName containerName: String, cloudKit: Bool, author: String?) -> CoreDataPersistentStore { private let store: CoreDataPersistentStore
.init(
public var containerURLs: [URL]? {
store.containerURLs
}
public init(withName containerName: String, cloudKit: Bool, author: String?) {
store = .init(
withName: containerName, withName: containerName,
model: profilesDataModel, model: Self.dataModel,
cloudKit: cloudKit, cloudKit: cloudKit,
author: author author: author
) )
} }
}
extension PassepartoutPersistence { public func profileRepository() -> ProfileRepository {
public static func profileRepository(_ store: CoreDataPersistentStore) -> ProfileRepository {
CDProfileRepository(store.context) CDProfileRepository(store.context)
} }
} }

View File

@ -31,7 +31,7 @@ import PassepartoutProviders
import XCTest import XCTest
final class ProvidersTests: XCTestCase { final class ProvidersTests: XCTestCase {
private var persistence: CoreDataPersistentStore! private var persistence: ProvidersPersistence!
private var manager: ProviderManager! private var manager: ProviderManager!
@ -39,16 +39,16 @@ final class ProvidersTests: XCTestCase {
override func setUp() { override func setUp() {
let model = NSManagedObjectModel.mergedModel(from: [.module])! let model = NSManagedObjectModel.mergedModel(from: [.module])!
persistence = CoreDataPersistentStore(withName: "ProvidersTests", model: model, cloudKit: false, author: nil) persistence = ProvidersPersistence(withName: "ProvidersTests", cloudKit: false, author: nil)
let remoteStrategy = APIRemoteProvidersStrategy( let remoteStrategy = APIRemoteProvidersStrategy(
appBuild: 10000, appBuild: 10000,
bundleServices: APIWebServices.bundledServices(withVersion: "v5"), bundleServices: APIWebServices.bundledServices(withVersion: "v5"),
remoteServices: APIWebServices("v5", URL(string: "https://passepartoutvpn.app/api/")!, timeout: nil), remoteServices: APIWebServices("v5", URL(string: "https://passepartoutvpn.app/api/")!, timeout: nil),
webServicesRepository: PassepartoutPersistence.webServicesRepository(persistence) webServicesRepository: persistence.webServicesRepository()
) )
manager = ProviderManager( manager = ProviderManager(
localProvidersRepository: PassepartoutPersistence.localProvidersRepository(persistence), localProvidersRepository: persistence.localProvidersRepository(),
remoteProvidersStrategy: remoteStrategy remoteProvidersStrategy: remoteStrategy
) )
// persistence.truncate() // persistence.truncate()