Added logic to use the setting if it's already been sent in a config
Added the ability to define requirements for migrations (in case some data or state needs to be loaded for a migration to be able to be performed correctly)
This commit is contained in:
parent
9c9fb09254
commit
ef5aa927a0
|
@ -517,6 +517,7 @@
|
|||
FD1C98E4282E3C5B00B76F9E /* UINavigationBar+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */; };
|
||||
FD1D732A2A85AA2000E3F410 /* Setting+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1D73292A85AA2000E3F410 /* Setting+Utilities.swift */; };
|
||||
FD1D732E2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1D732D2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift */; };
|
||||
FD1F9C9F2A862BE60050F671 /* MigrationRequirement.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */; };
|
||||
FD23CE1B2A651E6D0000B97C /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE1A2A651E6D0000B97C /* NetworkType.swift */; };
|
||||
FD23CE1F2A65269C0000B97C /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE1E2A65269C0000B97C /* Crypto.swift */; };
|
||||
FD23CE222A661D000000B97C /* OpenGroupAPI+Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE212A661D000000B97C /* OpenGroupAPI+Crypto.swift */; };
|
||||
|
@ -1675,6 +1676,7 @@
|
|||
FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FD1D73292A85AA2000E3F410 /* Setting+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Setting+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FD1D732D2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _015_BlockCommunityMessageRequests.swift; sourceTree = "<group>"; };
|
||||
FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationRequirement.swift; sourceTree = "<group>"; };
|
||||
FD23CE1A2A651E6D0000B97C /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = "<group>"; };
|
||||
FD23CE1E2A65269C0000B97C /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = "<group>"; };
|
||||
FD23CE212A661D000000B97C /* OpenGroupAPI+Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupAPI+Crypto.swift"; sourceTree = "<group>"; };
|
||||
|
@ -3671,6 +3673,7 @@
|
|||
children = (
|
||||
FD17D7BE27F51F8200122BE0 /* ColumnExpressible.swift */,
|
||||
FD17D7B727F51ECA00122BE0 /* Migration.swift */,
|
||||
FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */,
|
||||
FD17D7B927F51F2100122BE0 /* TargetMigrations.swift */,
|
||||
FD17D7C027F5200100122BE0 /* TypedTableDefinition.swift */,
|
||||
FD37EA1028AB34B3003AE748 /* TypedTableAlteration.swift */,
|
||||
|
@ -5678,6 +5681,7 @@
|
|||
FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */,
|
||||
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
|
||||
FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */,
|
||||
FD1F9C9F2A862BE60050F671 /* MigrationRequirement.swift in Sources */,
|
||||
FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */,
|
||||
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
|
||||
FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */,
|
||||
|
|
|
@ -10,6 +10,7 @@ enum _015_BlockCommunityMessageRequests: Migration {
|
|||
static let identifier: String = "BlockCommunityMessageRequests"
|
||||
static let needsConfigSync: Bool = false
|
||||
static let minExpectedRunDuration: TimeInterval = 0.01
|
||||
static var requirements: [MigrationRequirement] = [.sessionUtilStateLoaded]
|
||||
|
||||
static func migrate(_ db: Database) throws {
|
||||
// Add the new 'Profile' properties
|
||||
|
@ -25,7 +26,17 @@ enum _015_BlockCommunityMessageRequests: Migration {
|
|||
Identity.userExists(db),
|
||||
(try Setting.exists(db, id: Setting.BoolKey.checkForCommunityMessageRequests.rawValue)) == false
|
||||
{
|
||||
db[.checkForCommunityMessageRequests] = true
|
||||
let rawBlindedMessageRequestValue: Int32 = try SessionUtil
|
||||
.config(for: .userProfile, publicKey: getUserHexEncodedPublicKey(db))
|
||||
.wrappedValue
|
||||
.map { conf -> Int32 in try SessionUtil.rawBlindedMessageRequestValue(in: conf) }
|
||||
.defaulting(to: -1)
|
||||
|
||||
// Use the value in the config if we happen to have one, otherwise use the default
|
||||
db[.checkForCommunityMessageRequests] = (rawBlindedMessageRequestValue < 0 ?
|
||||
true :
|
||||
(rawBlindedMessageRequestValue > 0)
|
||||
)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
|
|
|
@ -210,6 +210,22 @@ internal extension SessionUtil {
|
|||
return updated
|
||||
}
|
||||
|
||||
static func hasSetting(_ db: Database, forKey key: String) throws -> Bool {
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
|
||||
// Currently the only synced setting is 'checkForCommunityMessageRequests'
|
||||
switch key {
|
||||
case Setting.BoolKey.checkForCommunityMessageRequests.rawValue:
|
||||
return try SessionUtil
|
||||
.config(for: .userProfile, publicKey: userPublicKey)
|
||||
.wrappedValue
|
||||
.map { conf -> Bool in (try SessionUtil.rawBlindedMessageRequestValue(in: conf) >= 0) }
|
||||
.defaulting(to: false)
|
||||
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
static func updatingSetting(_ db: Database, _ updated: Setting?) throws {
|
||||
// Don't current support any nullable settings
|
||||
guard let updatedSetting: Setting = updated else { return }
|
||||
|
|
|
@ -186,3 +186,13 @@ internal extension SessionUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Direct Values
|
||||
|
||||
extension SessionUtil {
|
||||
static func rawBlindedMessageRequestValue(in conf: UnsafeMutablePointer<config_object>?) throws -> Int32 {
|
||||
guard conf != nil else { throw SessionUtilError.nilConfigObject }
|
||||
|
||||
return user_profile_get_blinded_msgreqs(conf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,10 @@ open class Storage {
|
|||
|
||||
fileprivate var dbWriter: DatabaseWriter?
|
||||
internal var testDbWriter: DatabaseWriter? { dbWriter }
|
||||
private var unprocessedMigrationRequirements: Atomic<[MigrationRequirement]> = Atomic(MigrationRequirement.allCases)
|
||||
private var migrator: DatabaseMigrator?
|
||||
private var migrationProgressUpdater: Atomic<((String, CGFloat) -> ())>?
|
||||
private var migrationRequirementProcesser: Atomic<(Database?, MigrationRequirement) -> ()>?
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
|
@ -77,6 +79,7 @@ open class Storage {
|
|||
migrationTargets: (customMigrationTargets ?? []),
|
||||
async: false,
|
||||
onProgressUpdate: nil,
|
||||
onMigrationRequirement: { _, _ in },
|
||||
onComplete: { _, _ in }
|
||||
)
|
||||
return
|
||||
|
@ -148,6 +151,7 @@ open class Storage {
|
|||
migrationTargets: [MigratableTarget.Type],
|
||||
async: Bool = true,
|
||||
onProgressUpdate: ((CGFloat, TimeInterval) -> ())?,
|
||||
onMigrationRequirement: @escaping (Database?, MigrationRequirement) -> (),
|
||||
onComplete: @escaping (Swift.Result<Void, Error>, Bool) -> ()
|
||||
) {
|
||||
guard isValid, let dbWriter: DatabaseWriter = dbWriter else {
|
||||
|
@ -232,13 +236,24 @@ open class Storage {
|
|||
onProgressUpdate?(totalProgress, totalMinExpectedDuration)
|
||||
}
|
||||
})
|
||||
self.migrationRequirementProcesser = Atomic(onMigrationRequirement)
|
||||
|
||||
// Store the logic to run when the migration completes
|
||||
let migrationCompleted: (Swift.Result<Void, Error>) -> () = { [weak self] result in
|
||||
// Process any unprocessed requirements which need to be processed before completion
|
||||
// then clear out the state
|
||||
self?.unprocessedMigrationRequirements.wrappedValue
|
||||
.filter { $0.shouldProcessAtCompletionIfNotRequired }
|
||||
.forEach { self?.migrationRequirementProcesser?.wrappedValue(nil, $0) }
|
||||
self?.migrationsCompleted.mutate { $0 = true }
|
||||
self?.migrationProgressUpdater = nil
|
||||
self?.migrationRequirementProcesser = nil
|
||||
SUKLegacy.clearLegacyDatabaseInstance()
|
||||
|
||||
// Reset in case there is a requirement on a migration which runs when returning from
|
||||
// the background
|
||||
self?.unprocessedMigrationRequirements.mutate { $0 = MigrationRequirement.allCases }
|
||||
|
||||
// Don't log anything in the case of a 'success' or if the database is suspended (the
|
||||
// latter will happen if the user happens to return to the background too quickly on
|
||||
// launch so is unnecessarily alarming, it also gets caught and logged separately by
|
||||
|
@ -288,6 +303,22 @@ open class Storage {
|
|||
}
|
||||
}
|
||||
|
||||
public func willStartMigration(_ db: Database, _ migration: Migration.Type) {
|
||||
let unprocessedRequirements: Set<MigrationRequirement> = migration.requirements.asSet()
|
||||
.intersection(unprocessedMigrationRequirements.wrappedValue.asSet())
|
||||
|
||||
// No need to do anything if there are no unprocessed requirements
|
||||
guard !unprocessedRequirements.isEmpty else { return }
|
||||
|
||||
// Process all of the requirements for this migration
|
||||
unprocessedRequirements.forEach { migrationRequirementProcesser?.wrappedValue(db, $0) }
|
||||
|
||||
// Remove any processed requirements from the list (don't want to process them multiple times)
|
||||
unprocessedMigrationRequirements.mutate {
|
||||
$0 = Array($0.asSet().subtracting(migration.requirements.asSet()))
|
||||
}
|
||||
}
|
||||
|
||||
public static func update(
|
||||
progress: CGFloat,
|
||||
for migration: Migration.Type,
|
||||
|
|
|
@ -8,17 +8,21 @@ public protocol Migration {
|
|||
static var identifier: String { get }
|
||||
static var needsConfigSync: Bool { get }
|
||||
static var minExpectedRunDuration: TimeInterval { get }
|
||||
static var requirements: [MigrationRequirement] { get }
|
||||
|
||||
static func migrate(_ db: Database) throws
|
||||
}
|
||||
|
||||
public extension Migration {
|
||||
static var requirements: [MigrationRequirement] { [] }
|
||||
|
||||
static func loggedMigrate(
|
||||
_ storage: Storage?,
|
||||
targetIdentifier: TargetMigrations.Identifier
|
||||
) -> ((_ db: Database) throws -> ()) {
|
||||
return { (db: Database) in
|
||||
SNLogNotTests("[Migration Info] Starting \(targetIdentifier.key(with: self))")
|
||||
storage?.willStartMigration(db, self)
|
||||
storage?.internalCurrentlyRunningMigration.mutate { $0 = (targetIdentifier, self) }
|
||||
defer { storage?.internalCurrentlyRunningMigration.mutate { $0 = nil } }
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
||||
import Foundation
|
||||
|
||||
public enum MigrationRequirement: CaseIterable {
|
||||
case sessionUtilStateLoaded
|
||||
|
||||
var shouldProcessAtCompletionIfNotRequired: Bool {
|
||||
switch self {
|
||||
case .sessionUtilStateLoaded: return true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -82,6 +82,20 @@ public enum AppSetup {
|
|||
SNUIKit.self
|
||||
],
|
||||
onProgressUpdate: migrationProgressChanged,
|
||||
onMigrationRequirement: { db, requirement in
|
||||
switch requirement {
|
||||
case .sessionUtilStateLoaded:
|
||||
guard Identity.userExists(db) else { return }
|
||||
|
||||
// After the migrations have run but before the migration completion we load the
|
||||
// SessionUtil state
|
||||
SessionUtil.loadState(
|
||||
db,
|
||||
userPublicKey: getUserHexEncodedPublicKey(db),
|
||||
ed25519SecretKey: Identity.fetchUserEd25519KeyPair(db)?.secretKey
|
||||
)
|
||||
}
|
||||
},
|
||||
onComplete: { result, needsConfigSync in
|
||||
// After the migrations have run but before the migration completion we load the
|
||||
// SessionUtil state and update the 'needsConfigSync' flag based on whether the
|
||||
|
@ -93,6 +107,8 @@ public enum AppSetup {
|
|||
)
|
||||
}
|
||||
|
||||
// The 'needsConfigSync' flag should be based on whether either a migration or the
|
||||
// configs need to be sync'ed
|
||||
migrationsCompletion(result, (needsConfigSync || SessionUtil.needsSync))
|
||||
|
||||
// The 'if' is only there to prevent the "variable never read" warning from showing
|
||||
|
|
Loading…
Reference in New Issue