Skip to content

Dependency Injection: Improve injection of main database #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cryptomator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@
4AF45359271F38FC00CF1919 /* RenameVaultViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF45358271F38FC00CF1919 /* RenameVaultViewModelTests.swift */; };
4AF4535D27205F6200CF1919 /* VaultDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF4535C27205F6200CF1919 /* VaultDetailCoordinator.swift */; };
4AF4535F272066A600CF1919 /* RenameVaultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF4535E272066A600CF1919 /* RenameVaultViewController.swift */; };
4AF91A0F2AC2F025002357BA /* Dependencies in Frameworks */ = {isa = PBXBuildFile; productRef = 4AF91A0E2AC2F025002357BA /* Dependencies */; };
4AF91CBE25A63FD600ACF01E /* VaultListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF91CBD25A63FD600ACF01E /* VaultListViewModel.swift */; };
4AF91CC725A6437000ACF01E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AF91CC625A6437000ACF01E /* Colors.xcassets */; };
4AF91CD025A71C5800ACF01E /* UIImage+CloudProviderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF91CCF25A71C5800ACF01E /* UIImage+CloudProviderType.swift */; };
Expand Down Expand Up @@ -1095,6 +1096,7 @@
buildActionMask = 2147483647;
files = (
4A91728B2619F1D0003C4043 /* CryptomatorCommonCore in Frameworks */,
4AF91A0F2AC2F025002357BA /* Dependencies in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2220,6 +2222,7 @@
name = CryptomatorFileProvider;
packageProductDependencies = (
4A91728A2619F1D0003C4043 /* CryptomatorCommonCore */,
4AF91A0E2AC2F025002357BA /* Dependencies */,
);
productName = CryptomatorFileProvider;
productReference = 740375D72587AE7A0023FF53 /* libCryptomatorFileProvider.a */;
Expand Down Expand Up @@ -3705,6 +3708,10 @@
package = 4AED9A6D286B38D900352951 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
productName = Introspect;
};
4AF91A0E2AC2F025002357BA /* Dependencies */ = {
isa = XCSwiftPackageProductDependency;
productName = Dependencies;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 4A5E5B212453119100BD6298 /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@
"version": "2.0.0"
}
},
{
"package": "Dependencies",
"repositoryURL": "https://github.com/PhilLibs/simple-swift-dependencies",
"state": {
"branch": null,
"revision": "36e2e7732b5fe2bfec76e4af78d2ef532fe09456",
"version": "0.1.0"
}
},
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
Expand All @@ -189,6 +198,15 @@
"revision": "5b830d6ce6c34bb4bb976917576ab560e7945037",
"version": "3.3.4"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state": {
"branch": null,
"revision": "23cbf2294e350076ea4dbd7d5d047c1e76b03631",
"version": "1.0.2"
}
}
]
},
Expand Down
16 changes: 1 addition & 15 deletions Cryptomator/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
setupIAP()

// Set up database
guard let dbURL = CryptomatorDatabase.sharedDBURL else {
// MARK: Handle error
DatabaseManager.shared = DatabaseManager()

DDLogError("dbURL is nil")
return false
}
do {
let dbPool = try CryptomatorDatabase.openSharedDatabase(at: dbURL)
CryptomatorDatabase.shared = try CryptomatorDatabase(dbPool)
DatabaseManager.shared = try DatabaseManager(dbPool: dbPool)
} catch {
// MARK: Handle error

DDLogError("Initializing CryptomatorDatabase failed with error: \(error)")
return false
}
VaultDBManager.shared.recoverMissingFileProviderDomains().catch { error in
DDLogError("Recover missing FileProvider domains failed with error: \(error)")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// TableViewCellViewModel.swift
// BindableTableViewCellViewModel.swift
// Cryptomator
//
// Created by Philipp Schmid on 29.07.21.
Expand Down
21 changes: 9 additions & 12 deletions Cryptomator/Common/DatabaseManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@

import Combine
import CryptomatorCommonCore
import Dependencies
import Foundation
import GRDB

class DatabaseManager {
public static var shared: DatabaseManager!

let dbPool: DatabasePool

init(dbPool: DatabasePool) throws {
self.dbPool = dbPool
}
@Dependency(\.database) private var database

func getAllVaults() throws -> [VaultInfo] {
try dbPool.read { db in
try database.read { db in
let request = VaultAccount.including(required: VaultAccount.delegateAccount).including(required: VaultAccount.vaultListPosition)
return try VaultInfo.fetchAll(db, request)
}
Expand All @@ -35,7 +32,7 @@ class DatabaseManager {
for i in tempPositions.indices {
tempPositions[i].position = nil
}
try dbPool.write { db in
try database.write { db in
try db.execute(sql: "PRAGMA ignore_check_constraints=YES")
for position in tempPositions {
try position.update(db)
Expand All @@ -51,18 +48,18 @@ class DatabaseManager {
let observation = ValueObservation
.tracking { try VaultAccount.fetchAll($0) }
.removeDuplicates()
return observation.start(in: dbPool, scheduling: .immediate, onError: onError, onChange: onChange)
return observation.start(in: database, scheduling: .immediate, onError: onError, onChange: onChange)
}

func observeVaultAccount(withVaultUID vaultUID: String, onError: @escaping (Error) -> Void, onChange: @escaping (VaultAccount?) -> Void) -> DatabaseCancellable {
let observation = ValueObservation.tracking { db in
try VaultAccount.fetchOne(db, key: vaultUID)
}
return observation.start(in: dbPool, scheduling: .immediate, onError: onError, onChange: onChange)
return observation.start(in: database, scheduling: .immediate, onError: onError, onChange: onChange)
}

func getAllAccounts(for cloudProviderType: CloudProviderType) throws -> [AccountInfo] {
try dbPool.read { db in
try database.read { db in
let accountWithCloudProviderType = AccountListPosition.account.filter(Column("cloudProviderType") == cloudProviderType)
let request = AccountListPosition.including(required: accountWithCloudProviderType).order(Column("position"))
return try AccountInfo.fetchAll(db, request)
Expand All @@ -77,7 +74,7 @@ class DatabaseManager {
for i in tempPositions.indices {
tempPositions[i].position = nil
}
try dbPool.write { db in
try database.write { db in
try db.execute(sql: "PRAGMA ignore_check_constraints=YES")
for position in tempPositions {
try position.update(db)
Expand All @@ -102,7 +99,7 @@ class DatabaseManager {
.removeDuplicates()
.map { rows in rows.map(AccountWithDisplayName.init(row:)) }
.map { annotatedAccounts in annotatedAccounts.map(\.account) }
return observation.start(in: dbPool, scheduling: .immediate, onError: onError, onChange: onChange)
return observation.start(in: database, scheduling: .immediate, onError: onError, onChange: onChange)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Cryptomator/Onboarding/OnboardingViewController.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// OnboardingWelcomeViewController.swift
// OnboardingViewController.swift
// Cryptomator
//
// Created by Tobias Hagemann on 08.09.21.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class VaultDetailUnlockVaultViewModel: SingleSectionTableViewModel, ReturnButton
}

func unlockVault() throws {
let cachedVault = try VaultDBCache(dbWriter: CryptomatorDatabase.shared.dbPool).getCachedVault(withVaultUID: vault.vaultUID)
let cachedVault = try VaultDBCache().getCachedVault(withVaultUID: vault.vaultUID)
let masterkeyFile = try MasterkeyFile.withContentFromData(data: cachedVault.masterkeyFileData)
_ = try masterkeyFile.unlock(passphrase: password)
try passwordManager.setPassword(password, forVaultUID: vault.vaultUID)
Expand Down
6 changes: 4 additions & 2 deletions CryptomatorCommon/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/cryptomator/cloud-access-swift.git", .upToNextMinor(from: "1.7.0")),
.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", .upToNextMinor(from: "3.8.0"))
.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", .upToNextMinor(from: "3.8.0")),
.package(url: "https://github.com/PhilLibs/simple-swift-dependencies", .upToNextMajor(from: "0.1.0"))
],
targets: [
.target(
Expand All @@ -41,7 +42,8 @@ let package = Package(
name: "CryptomatorCommonCore",
dependencies: [
"CocoaLumberjackSwift",
"CryptomatorCloudAccessCore"
"CryptomatorCloudAccessCore",
.product(name: "Dependencies", package: "simple-swift-dependencies")
]
),
.testTarget(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,74 @@
// Copyright © 2020 Skymatic GmbH. All rights reserved.
//

import CocoaLumberjackSwift
import Dependencies
import Foundation
import GRDB

private enum CryptomatorDatabaseKey: DependencyKey {
static let liveValue: DatabaseWriter = CryptomatorDatabase.live

static var testValue: DatabaseWriter {
let inMemoryDB = DatabaseQueue(configuration: .defaultCryptomatorConfiguration)
do {
try CryptomatorDatabase.migrator.migrate(inMemoryDB)
} catch {
DDLogError("Failed to migrate in-memory database: \(error)")
}
return inMemoryDB
}
}

public extension DependencyValues {
var database: DatabaseWriter {
get { self[CryptomatorDatabaseKey.self] }
set { self[CryptomatorDatabaseKey.self] = newValue }
}
}

private enum CryptomatorDatabaseLocationKey: DependencyKey {
static var liveValue: URL? { CryptomatorDatabase.sharedDBURL }
static var testValue: URL? { FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: false) }
}

public extension DependencyValues {
var databaseLocation: URL? {
get { self[CryptomatorDatabaseLocationKey.self] }
set { self[CryptomatorDatabaseLocationKey.self] = newValue }
}
}

public enum CryptomatorDatabaseError: Error {
case dbDoesNotExist
case incompleteMigration
}

public class CryptomatorDatabase {
public static var shared: CryptomatorDatabase!
static var live: DatabaseWriter {
@Dependency(\.databaseLocation) var databaseURL

public static var sharedDBURL: URL? {
let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: CryptomatorConstants.appGroupName)
return sharedContainer?.appendingPathComponent("db.sqlite")
guard let dbURL = databaseURL else {
fatalError("Could not get URL for shared database")
}
let database: DatabaseWriter
do {
database = try CryptomatorDatabase.openSharedDatabase(at: dbURL)
} catch {
DDLogError("Failed to open shared database: \(error)")
fatalError("Could not open shared database")
}
do {
try CryptomatorDatabase.migrator.migrate(database)
} catch {
DDLogError("Failed to migrate database: \(error)")
}
return database
}

public let dbPool: DatabasePool
private static var oldSharedDBURL: URL? {
static var sharedDBURL: URL? {
let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: CryptomatorConstants.appGroupName)
return sharedContainer?.appendingPathComponent("main.sqlite")
}

public init(_ dbPool: DatabasePool) throws {
self.dbPool = dbPool
try CryptomatorDatabase.migrator.migrate(dbPool)
return sharedContainer?.appendingPathComponent("db.sqlite")
}

static var migrator: DatabaseMigrator {
Expand All @@ -48,7 +91,7 @@ public class CryptomatorDatabase {
}

// swiftlint:disable:next function_body_length
public class func v1Migration(_ db: Database) throws {
class func v1Migration(_ db: Database) throws {
// Common
try db.create(table: "cloudProviderAccounts") { table in
table.column("accountUID", .text).primaryKey()
Expand Down Expand Up @@ -157,12 +200,10 @@ public class CryptomatorDatabase {
var coordinatorError: NSError?
var dbPool: DatabasePool?
var dbError: Error?
var configuration = Configuration()
// Workaround for a SQLite regression (see https://github.com/groue/GRDB.swift/issues/1171 for more details)
configuration.acceptsDoubleQuotedStringLiterals = true

coordinator.coordinate(writingItemAt: databaseURL, options: .forMerging, error: &coordinatorError, byAccessor: { _ in
do {
dbPool = try DatabasePool(path: databaseURL.path, configuration: configuration)
dbPool = try DatabasePool(path: databaseURL.path, configuration: .defaultCryptomatorConfiguration)
} catch {
dbError = error
}
Expand Down Expand Up @@ -193,7 +234,7 @@ public class CryptomatorDatabase {

private static func openReadOnlyDatabase(at databaseURL: URL) throws -> DatabasePool {
do {
var configuration = Configuration()
var configuration = Configuration.defaultCryptomatorConfiguration
configuration.readonly = true
let dbPool = try DatabasePool(path: databaseURL.path, configuration: configuration)

Expand All @@ -211,3 +252,12 @@ public class CryptomatorDatabase {
}
}
}

extension Configuration {
static var defaultCryptomatorConfiguration: Configuration {
var configuration = Configuration()
// Workaround for a SQLite regression (see https://github.com/groue/GRDB.swift/issues/1171 for more details)
configuration.acceptsDoubleQuotedStringLiterals = true
return configuration
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// File.swift
// FileProviderConnector.swift
// CryptomatorCommonCore
//
// Created by Philipp Schmid on 26.07.21.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright © 2020 Skymatic GmbH. All rights reserved.
//

import Dependencies
import Foundation
import GRDB

Expand Down Expand Up @@ -41,15 +42,11 @@ public protocol CloudProviderAccountManager {
}

public class CloudProviderAccountDBManager: CloudProviderAccountManager {
public static let shared = CloudProviderAccountDBManager(dbPool: CryptomatorDatabase.shared.dbPool)
private let dbPool: DatabasePool

init(dbPool: DatabasePool) {
self.dbPool = dbPool
}
@Dependency(\.database) var database
public static let shared = CloudProviderAccountDBManager()

public func getCloudProviderType(for accountUID: String) throws -> CloudProviderType {
let cloudAccount = try dbPool.read { db in
let cloudAccount = try database.read { db in
return try CloudProviderAccount.fetchOne(db, key: accountUID)
}
guard let providerType = cloudAccount?.cloudProviderType else {
Expand All @@ -59,7 +56,7 @@ public class CloudProviderAccountDBManager: CloudProviderAccountManager {
}

public func getAllAccountUIDs(for type: CloudProviderType) throws -> [String] {
let accounts: [CloudProviderAccount] = try dbPool.read { db in
let accounts: [CloudProviderAccount] = try database.read { db in
return try CloudProviderAccount
.filter(Column("cloudProviderType") == type)
.fetchAll(db)
Expand All @@ -68,13 +65,13 @@ public class CloudProviderAccountDBManager: CloudProviderAccountManager {
}

public func saveNewAccount(_ account: CloudProviderAccount) throws {
try dbPool.write { db in
try database.write { db in
try account.save(db)
}
}

public func removeAccount(with accountUID: String) throws {
try dbPool.write { db in
try database.write { db in
guard try CloudProviderAccount.deleteOne(db, key: accountUID) else {
throw CloudProviderAccountError.accountNotFoundError
}
Expand Down
Loading